Insert data in another table through entity framework MVC - asp.net-mvc

I want to save student's data in student table and their address in student details table i can't insert data in second table.
Error is Object reference not set to an instance of an object.
Student Model
public partial class Student
{
public int Id { get; set; }
public string Name { get; set; }
public Nullable<System.DateTime> CreatedDate { get; set; }
}
StudentDetails
public partial class StudentDetail
{
public int Id { get; set; }
public string Address { get; set; }
public Nullable<System.DateTime> CreatedDate { get; set; }
}
View Model
public class StudentViewModel
{
public Student Students { get; set; }
public StudentDetail StudentDetails { get; set; }
}
DbSet
public partial class SampleEntities : DbContext
{
public SampleEntities()
: base("name=SampleEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public System.Data.Entity.DbSet<Basics.Models.Student> Students { get; set; }
public System.Data.Entity.DbSet<Basics.Models.StudentDetail> StudentDetails { get; set; }
}
Controller
private SampleEntities db = new SampleEntities();
Action
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(StudentViewModel model)
{
if (ModelState.IsValid)
{
model.Students.CreatedDate = DateTime.Now;
db.Students.Add(model.Students);
db.SaveChanges();
//The Newly created Id gets created and when saving that Id in anothr table the exception comes
model.StudentDetails.Id = model.Students.Id;
//For Time Being in real time it won't be hard coded
model.StudentDetails.Address = "New Jersey";
db.StudentDetails.Add(model.StudentDetails);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(model.Students);
}

Why not have
public StudentDetail StudentDetails { get; set; }
in Student class and change Id for
public int StudentId { get; set; }
and then change Id in StudentDetail for also
public int StudentId { get; set; }
Like that Entity Framework will be able to join them in a 1 to 1 relationship. You'll have to add some primary keys/foreign keys depending on your needs.

Related

How to create own/custom controller in Codefirst approach in entity framework

I am trying to make a sample application using code first approach in MVC so I don't have any database. Now I have setup all class files and context class. In next step I have created a controller(Emplty) and want to create own Create/List/Delete functionalities. How can I do it.
Some of the codes are below
public class Employee
{
public int EmployeeID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public int DepartmentID { get; set; }//Foreign Key
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
public class Department
{
public int DepartmentID { get; set; }
public string DepartmentName { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
public class EmployeeDBContext: DbContext
{
public EmployeeDBContext()
: base("EmployeeDBContext")//EmployeeDBContext will be name of database.
{ }
public virtual DbSet<Employee> Employees { get; set; }
public virtual DbSet<Department> Departments { get; set; }
public virtual DbSet<Enrollment> Enrollments { get; set; }
}
public class EmployeeInitializer:DropCreateDatabaseIfModelChanges<EmployeeDBContext>
{
protected override void Seed(EmployeeDBContext context)
{
var employee = new List<Employee>
{
new Employee{EmployeeID=1, Name="Aman", Age=15, DepartmentID=11},
new Employee {EmployeeID=2, Name="Supriya", Age=12, DepartmentID=22},
new Employee {EmployeeID=3, Name="Rishabh", Age=10, DepartmentID=44}
};
employee.ForEach(x => context.Employees.Add(x));
context.SaveChanges();
var department = new List<Department> {
new Department{DepartmentID=11, DepartmentName="IT"},
new Department{DepartmentID=22, DepartmentName="HR"},
new Department{DepartmentID=33, DepartmentName="Mechanical"},
new Department{DepartmentID=44, DepartmentName="NGO"}
};
department.ForEach(x=>context.Departments.Add(x));
context.SaveChanges();
var enrollment = new List<Enrollment>() {
new Enrollment{EnrollmentID=111, EmployeeID=1, DepartmentID=11},
new Enrollment{EnrollmentID=222, EmployeeID=3, DepartmentID=44},
new Enrollment{EnrollmentID=333, EmployeeID=2, DepartmentID=22}
};
enrollment.ForEach(x=>context.Enrollments.Add(x));
context.SaveChanges();
}
}
I wish to add code from below controller onward
public ActionResult CreateEmployee(Employee employee)
{
//my desired code here
return View();
}
[HttpGet]
public ActionResult ListEmployee()
{
//my desired code here
return View();
}
you mean how to do something like:
[HttpGet]
public ActionResult ListEmployee()
{
//my desired code here
using(var context=new EmployeeDBContext())
{
return View(context. Employee.ToList());
}
}
[HttpPost]
[Route("api/Employee/CreateEmployee")]
public ActionResult CreateEmployee([FromBody]Employee employee)
{
//add to ef
_db.Add(employee);
_db.SaveChanges();
//my desired code here
return Ok();
}

Navigation property not getting filled on lazy loading

I am trying my hands-on on mvc examples given on Mvc Offical Site.
Here i have 3 Models Student,Course and Enrollment where there is an one to many relationship on Course and Enrollment entities and many to one relationship on Enrollment and student.
The models for Student,Course and Enrollment are as follows with the navigation properties marked as "virtual" since i need to perform lazy binding
public class Student
{
public int StudentID { get;set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public DateTime EnrollmentDate { get; set; }
public virtual IEnumerable<Enrollment> Enrollments { get; set; }
}
In the same way i have my course model
My Enrollment Model
public class Enrollment
{
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
// public Grade? Grade { get; set; }
public virtual Course Course { get; set; }
public virtual Student Student { get; set; }
}
I am using Code-First Technique With EF 5.My DB Context Class is as follows
public class SchoolContext:DbContext
{
public DbSet<Student> Students { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Course> Courses { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
By Scaffolding I have generated all my views .On Click of my details Action link I have a controller function that is called
public ActionResult Details(int id = 0)
{
db.Configuration.LazyLoadingEnabled = true;
db.Configuration.ProxyCreationEnabled = true;
Student student = db.Students.Find(id);
// db.Entry(student).Reference(p => p.Enrollments).Load();
IEnumerable<Enrollment> s= student.Enrollments;
if (student == null)
{
return HttpNotFound();
}
return View(student);
}
Here the problem is when the Find() method is called in the controller the navigation property in Student Class model is null.But there is data in DB corresponding to the id that is being passed.In short,the navigation property is not returning data(null).
You have to materialize the entities to get a rid of the current lazy loading in the query:
Student student = db.Students.Find(id).ToList();
This will fix your problem without ToList() after db.Students.Find(id); = will returns the generated object from the dynamic proxy.
Second problem you have a casting bug:
IEnumerable<Enrollment> enrollments = student.Enrollments; // is wrong
should be:
ICollection<State> enrollments = student.Enrollments;
or
var enrollments = student.Enrollments;

how to query against a many to many relation with entity framework 6

I have those 2 Models
public class BranchEmployees
{
public int ID { get; set; }
[Required, Column(Order = 0), Key]
public string ApplicationUserID { get; set; }
[Required, Column(Order = 1), Key]
public int BranchID { get; set; }
public virtual ICollection<ApplicationUser> ApplicationUser { get; set; }
public virtual ICollection<Branch> Branch { get; set; }
}
public class Branch
{
public int ID { get; set; }
public string BranchName { get; set; }
[Required]
public string ApplicationUserID { get; set; }
public ApplicationUser User { get; set; }
public virtual ICollection<BranchEmployees> BranchEmployees { get; set; }
}
public class ApplicationUser
{
//rest of the code
}
UPDATE
I have everything set up but what I want is the query that gets me the Employees whose IDs are in the branch employees table
, I'm using entity framework code first with MVC 5 , how do I do it ?
Assuming that your ApplicationUser class will have a navigational property called BranchEmployees, here is the query that gets me the Employees whose IDs are in the branch employees table
List<ApplicationUsers> employeeNames =
dbContext
.ApplicationUsers
.Where(au => au.BranchEmployees
.Count() > 0).ToList();
Also, can you provide whole model including ApplicationUser? I also wonder why you do not prefer BranchEmployees to inherit from ApplicationUser.
You don't need a class that indicates a many-to-many relation between two tables when you do code-first. The key here is to create virtual properties of those classes. Lets say you have a class Student and class Course. Students can be in many Courses and Courses can have many Students. To generate a database using these models the classes should look like this:
public class Student
{
private ICollection<Course> _courses;
public Student()
{
this._courses = new HashSet<Course>();
}
[Key]
public int Id { get; set; }
public string FullName { get; set; }
public virtual ICollection<Course> Courses
{
get { return this._courses; }
set { this._courses = value; }
}
}
And for Course:
public class Course
{
private ICollection<Student> _students;
public Course()
{
this._students = new HashSet<Student>();
}
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<Student> Students
{
get { return this._students; }
set { this._students = value; }
}
}
I hope that this can help you solve your issue.

MVC 5 Razor code-first EF Junction Table with IdentityUser

So I've got these 2 class and User coming from individual user accounts
public class User : IdentityUser
{
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public string Email { get; set; }
public virtual ICollection<Basket> Baskets { get; set; }
}
public class Basket
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Key]
public int BasketId { get; set; }
public string Name { get; set; }
public int Words { get; set; }
public virtual ICollection<User> Users { get; set; }
}
EF has created UserBaskets with 2 FK. I have items in my Basket class that I seeded.
My question is, how can I add row to my junction table in the controller? For example, a logged user click on a basket and return the Id...Now I've got
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Basket(int? basketid)
{
if (ModelState.IsValid)
{
var job = User.Identity.GetUserId();
job.Baskets.Add(basketid);
db.Users.Add(job);
db.SaveChanges();
return RedirectToAction("Basket");
}
return View(db.Baskets.ToList());
}
Thank you for any help.
I finally chose to add a junction table manually
public class UserBasket
{
[Key]
public int UserBasketId { get; set; }
public virtual User User { get; set; }
public virtual Basket Basket { get; set; }
public DateTime Date { get; set; }
}
and could add a row using identityUser like this
UserManager<User> userManager = new UserManager<User>(new UserStore<User>(db));
var user = userManager.FindById(User.Identity.GetUserId());
Basket basket = db.Basket.Find(id);
var userbasket = new UserBasket {User = user, Basket = basket, Date = DateTime.Now };
db.UserBasket.Add(userbasket);
db.SaveChanges();

Saving Viewmodel data to the Database in ASP.NET MVC

I am new to ASP.net MVC and am using a viewmodel rather than viewbags to populate my dropdowns since I've seen most people recommend against them. I have a slick UI that does cascading dropdowns and autocompletes (not shown here) but I can't seem to get my data saved back to the database.
Models:
public partial class Car
{
public int CarID { get; set; }
public string CarName { get; set; }
public int ModelID { get; set; }
public int ManufacturerID { get; set; }
public int CarColorID { get; set; }
public Nullable<decimal> Price { get; set; }
public string Description { get; set; }
public virtual CarColor CarColor { get; set; }
public virtual Manufacturer Manufacturer { get; set; }
public virtual CarModel CarModel { get; set; }
}
public partial class CarColor
{
public CarColor()
{
this.Cars = new HashSet<Car>();
}
public int ColorID { get; set; }
public string ColorName { get; set; }
public virtual ICollection<Car> Cars { get; set; }
}
public partial class CarModel
{
public CarModel()
{
this.Cars = new HashSet<Car>();
}
public int CarModelID { get; set; }
public int ManufacturerID { get; set; }
public string CarModelName { get; set; }
public virtual ICollection<Car> Cars { get; set; }
public virtual Manufacturer Manufacturer { get; set; }
}
public partial class Manufacturer
{
public Manufacturer()
{
this.Cars = new HashSet<Car>();
this.Manufacturer1 = new HashSet<Manufacturer>();
this.CarModels = new HashSet<CarModel>();
}
public int ManufacturerID { get; set; }
public string ManufacturerName { get; set; }
public Nullable<int> ParentID { get; set; }
public virtual ICollection<Car> Cars { get; set; }
public virtual ICollection<Manufacturer> Manufacturer1 { get; set; }
public virtual Manufacturer Manufacturer2 { get; set; }
public virtual ICollection<CarModel> CarModels { get; set; }
}
ViewModel:
public class AnotherTestViewModel
{
public Car car { get; set; }
public IEnumerable<SelectListItem> CarModels { get; set; }
public IEnumerable<SelectListItem> Manufacturers { get; set; }
public IEnumerable<SelectListItem> CarColors { get; set; }
}
Controller:
public ActionResult Create()
{
var model = new AnotherTestViewModel();
using (new CarTestEntities())
{
model.CarModels = db.CarModels.ToList().Select(x => new SelectListItem
{
Value = x.CarModelID.ToString(),
Text = x.CarModelName
});
model.Manufacturers = db.Manufacturers.ToList().Select(x => new SelectListItem
{
Value = x.ManufacturerID.ToString(),
Text = x.ManufacturerName
});
model.CarColors = db.CarColors.ToList().Select(x => new SelectListItem
{
Value = x.ColorID.ToString(),
Text = x.ColorName
});
}
return View(model);
}
//
// POST: /AnotherTest/Create
[HttpPost]
public ActionResult Create(AnotherTestViewModel model)
{
if (ModelState.IsValid)
{
db.Entry(model).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Details", "AnotherTestViewModel", new { id = model.car.CarID });
}
return View();
}
I saw a few recommendations to use Automapper because EntityState.Modified won't work, but I'm not sure how to configure it because using the code below didn't work.
Mapper.CreateMap<AnotherTestViewModel, Car>();
Mapper.CreateMap<Car, AnotherTestViewModel>();
var newCar = Mapper.Map<AnotherTestViewModel, Car>(model);
Any ideas?
Your view model should not be interacting with the database. View Models should only be used in the presentation layer (user interface) - hence the term "View" model. You should have another model (data model) that interacts with your database. Then you should have some type of service layer that handles your conversion between your view model and your data model (and vice versa). Your data model is the model generated by Entity Framework (which I assume is what you are using). To handle updates to your database, you need to instantiate a data context, grab the data entity from your database, make changes to that entity, and call save changes all in that data context. The data context will keep track of all changes to your entities and apply the necessary changes to your database when you call "save changes".
Example:
public void UpdateCar(CarViewModel viewModel)
{
using (DataContext context = new DataContext())
{
CarEntity dataModel = context.CarEntities.where(x => x.Id == viewModel.Id).First();
dataModel.Name = viewModel.Name;
dataModel.Type = viewModel.Type;
context.SaveChanges();
}
}
In this example, context will keep track of any changes to "dataModel". When "context.SaveChanges" is called, those changes will automatically be applied to the database.

Resources