0

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 inside AddCar()).
  • 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

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 of PersonModel is not a direct reference to DbContext, but rather loaded and stored in a List (or similar) in some other class (e.g. a ViewModel)? – Noceo Apr 9 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 Apr 10 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. – Noceo Apr 10 at 6:42
  • 1
    First, 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, call AddCar method. – Engineert Apr 10 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. – Noceo Apr 10 at 7:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.