I was wondering how to updated nested objects/sub-properties when using Entity Framework. But to make things clear, let's start with an example.
I have an object, which can own a number of other objects. In other words, an object which contains a list of a different type of objects. This could be a person, who has multiple cars.
public class PersonModel
{
// ...
public List<CarModel> Cars { get; set; }
}
Now I want to make a service with a method called AddCar()
, but I am a bit puzzled on what goes inside this method. It could look something like this:
public void AddCar(PersonModel owner, CarModel car)
{
car.OwnerId = owner.Id;
var ctx = GetDbContext();
ctx.Cars.Add(car);
ctx.SaveChanges();
}
Obviously this is a bit simplified, but you get the point. The problem in the example above is that the owner does not get updated. The new car will not be added to List<CarModel> Cars
, until the person is re-loaded from the database.
This must be a common issue, so I suppose there is some sort of standard way of dealing with this. I just have not been able to find it. Here are the different solutions I can think of:
- Make a method for updating the person from the database, which is called inside
AddCar()
(after adding the car). - Alter the object
owner
by adding the car to the list of cars, on top of adding it to the database (also insideAddCar()
). - Add the new car to the list of cars inside
owner
and then make an update function which handles updating the owner, and all of its nested objects.
I cannot see any clear winnder in the suggestions above. Maybe it's something completely different? Any advice would be much appreciated.
1 Answer 1
This is totally up to your design. If you want to use Entity Framework AutoDetectChangesEnabled feature, it can be track changes and store for you. This property default value is true.
public PersonModel Person()
{
// navigation property virtual ICollection<T>
public virtual ICollection<CarModel> Cars { get; set; }
}
public void AddCar(PersonModel owner, CarModel car)
{
var ctx = GetDbContext();
PersonModel person = ctx.person.GetPerson(owner.Id);
// this is entity object and entity framework will track the changes.
// so when you add a car to person, then you can call save changes method
person.Cars.Add(car);
ctx.SaveChanges();
foreach(CarModel car in person.Cars.ToList())
{
// Id will not be empty.
Console.WriteLine(car.Id);
}
}
Otherwise, you need to manage it manually:
public void AddCar(PersonModel owner, CarModel car)
{
car.OwnerId = owner.Id;
var ctx = GetDbContext();
ctx.Cars.Add(car);
ctx.SaveChanges();
owner.Cars.Add(car);
}
I assume PersonModel
is reference type. So, this referenced type instance owner
includes new car. You can reach it from where you call AddCar
method.
Note: I changed your Cars property to Navigation Propery. This is the best way to manage model relations(also table relations). Look at also Lazy Loading with Entity Framework.
-
What if the
owner
instance ofPersonModel
is not a direct reference toDbContext
, but rather loaded and stored in aList
(or similar) in some other class (e.g. a ViewModel)?Jakob Busk Sørensen– Jakob Busk Sørensen04/09/2019 18:48:52Commented Apr 9, 2019 at 18:48 -
@Noceo if your PersonModel is ViewModel, you should manage everything with Entity Model and then map to ViewModel. Having relation(s) to Entity Model from View Model is really bad practice. ViewModel is for your view and EntityModel is for your Data Access Layer and Business Logic Layer(up to your design) and these layers may not have a direct realtion to view and may not know each others. You can find more reason why you shouldn't create kind of realations.Engineert– Engineert04/10/2019 06:37:30Commented Apr 10, 2019 at 6:37
-
I have a
ObservableCollection<PersonModel> Persons
in my ViewModel. It is populated by a method, which gets persons from the database (via EF) and inserts them into the collection. So from what I can tell, there is no link from the ViewModel to the data layer.Jakob Busk Sørensen– Jakob Busk Sørensen04/10/2019 06:42:12Commented Apr 10, 2019 at 6:42 -
1First, if you have kind of populate method, then you can call your CRUD operation from this method and can return collection from there by mapping EntityModel to ViewModel . Second, as I see, your
AddCar
method is DAL method. So, this method should not know anything about your view models. You should map your PersonModel(ViewModel) to proper EntityModel. Then, callAddCar
method.Engineert– Engineert04/10/2019 06:50:57Commented Apr 10, 2019 at 6:50 -
Thank you for your comments. I think I might have an incorrect approach to Entity Framework altogether. I tend to have a ViewModel with its own collections which are then populated by refresh methods. This means being disconnected from the DbContext. And that is what is causing my problems. If you are supposed to link the ViewModel directly to the DbContext, that opens to some entirely different solutions. Like the one you show.Jakob Busk Sørensen– Jakob Busk Sørensen04/10/2019 07:24:30Commented Apr 10, 2019 at 7:24
Explore related questions
See similar questions with these tags.