1

I have two model classes:

public class Person {
        public int Id { get; set; }
        public string FirstName { get; set; }
       public virtual List<Desert> Deserts {get;set;}
}
public class Desert{
        public int Id { get; set; }
        public string Name { get; set; }
        public virtual List<Person> Persons{get;set}
}

If I add some persons to the database in Seed method and add their favourite deserts to them:

var deserts = new List<Desert>{new Desert{Name = "IceCream"}, new Desert{Name = "Cake"}}
var persons = new List<Person> { 
                         new Person{FirstName = "James", Deserts = deserts},
                         new Person{FirstName = "Joanna"}
                        };

                persons.ForEach(person => context.Persons.AddOrUpdate(person));
                context.SaveChanges();

Then somewhere in controller invoke method which removes desert from person(connection/relationship between person and desert) :

 //removes desert from a person
 public void RemoveDesert(int personId, int desertToRemoveId) {

            Person person = db.Persons.Find(personId);
            foreach(Desert desert in person.Deserts){
                    if(desert.Id == desertToRemoveId){
                      person.Deserts.Remove(desert);

                   }
            }
            context.saveChanges();
        }

Will Entity Framework see that property public virtual List<Desert> FavouriteDeserts {get;set;} changed and update it?

If not how to remove a desert which has Id=desertToRemoveId from a person which has Id=personId ans save changes in database? Can it be done without Lambda expressions?

Duke Nuke
  • 1,815
  • 3
  • 15
  • 14

1 Answers1

0

Yes, it keeps track of child objects unless you tell it not to.

foreach(Desert desert in person.Deserts){
                    if(desert.Id == desertToRemoveId){
                      person.Deserts.Remove(desert);

                   }
            }

I don't think C# will allow you to modify a collection while iterating it.

That said, you can always query the object you want to remove and then remove it:

var desertToRemove = person.Deserts.FirstOrDefault(x=> x.Id == desertToRemoveId);
if(desertToRemove != null) person.Deserts.Remove(desertToRemove );

Note that this however, only removes the relation (between person and desert), not the child entity. Read up on this subtle difference in this excellent answer here.

Also, you need to change your classes to use ICollection instead of List:

public virtual ICollection<Person> Persons {get; set; }
public virtual ICollection<Desert> Deserts {get; set;}
Community
  • 1
  • 1
Mrchief
  • 75,126
  • 20
  • 142
  • 189
  • Will Entity framework update tables after this command `person.Deserts.Remove(desertToRemove );`? Could it be done without Lambda expression I've seen on tutorials that people used SQLish methods in C#. – Duke Nuke Sep 02 '14 at 17:37
  • 1
    When you call `context.saveChanges();`, yes, it'll update the underlying tables. I'm not sure what those SQLish methods are and why you want to avoid lambda. – Mrchief Sep 02 '14 at 17:39
  • I try avoid lambda because I don't understand it, tried many times, don't get it... too stupid or sth ; [. I see from the context that `x` in expression is desert and it will return desert which `Id` is `desertToRemoveId`. But I never get this `=>`. Those SQLish methods like here in first paragraph: http://msdn.microsoft.com/pl-pl/data/jj573936.aspx – Duke Nuke Sep 02 '14 at 17:48
  • Oh and sorry for not upvoting I can't yet. – Duke Nuke Sep 02 '14 at 17:50
  • I see! :) Those are LINQ query syntax and lambdas are just a shortcut. They can be confusing initially and sometimes, those SQLish statements can read better! You can write those expressions and if you have ReSharper, you can see how they translate to lambdas. That's a good learning tool. Other than, you can use either and they make no difference in terms of execution or results. – Mrchief Sep 02 '14 at 17:50
  • I think you're bit confused here. When you say `person.Deserts.Remove` - you're saying remove this `desert` for the `person`. Now the opposite would imply - remove this `person` for this `desert`. See the difference? – Mrchief Sep 02 '14 at 17:54
  • Sorry your comment did not update earlier. Do I need remove relation between desert and person or EntityFramework will do it for me? I mean `desertToRemove.Persons.Remove(person);`? – Duke Nuke Sep 02 '14 at 18:00
  • You'll have to do it explicitly in this case. – Mrchief Sep 02 '14 at 18:01
  • Only very last thing, so if there is many to many relationship I have to delete manually both sides or there is a method like: `dbContext.Persons.Select(personId).Deserts.Remove(desertId)` and it automatically deletes associations on both sides? Sorry for asking and asking, I will no more : ), promise. – Duke Nuke Sep 02 '14 at 18:04
  • In this case, it'd lead to cyclical cascade deletes - desert removal triggers person removal which in turn triggers more desert removal and so on. But like I said, they are 2 different things. You need to ask what is it that you're trying to achieve? Person has no Strawberry Ice cream is very different from Strawberry ice cream has no person. – Mrchief Sep 02 '14 at 18:14
  • I want to remember for Person: deserts which person likes and for Desert: who(person) likes it. So If I remove connection person-->desert, I would also want to delete desert-->person because this desert is no more liked by this person. – Duke Nuke Sep 02 '14 at 18:17
  • If you just want the connection gone then you have to do it manually. EF's cascade delete triggers in on entity removal, not on relationship removal. – Mrchief Sep 02 '14 at 18:20