I have these POCO classes, they're mapped using Fluent API with a TPT (Table per Type) strategy.
public class Base
{
...
}
public class Derived : Base
{
...
public virtual ICollection<Foo> Foos {get; set;} // One-to-Many
}
public class Foo
{
...
public virtual ICollection<Bar> Bars {get; set;} // One-to-Many
}
public class Bar
{
...
}
My repository looks like this.
public class Repo
{
public void Update(Base item)
{
using (var ctx = new DbContext())
{
ctx.Entry(item).State = EntityState.Modified;
ctx.SaveChanges();
}
}
}
Action:
public void DoStuff()
{
Derived item = repo.GetById(1);
item.SomeProp = "xyz"; // new value
item.Foos = GenerateFoosWithBars(); // change children
repo.Update(item);
}
To my surprise Update
actually works if I'm only updating the Base
or Derived
classes. However things turn ugly when I try to update the One-to-Many relations. I found a tutorial on how to Update One-to-Many Entities in EF4. I was really expecting EF to be way smarter then this, I mean I have to do it manually... that's so unlike everything else in EF.
So I started out trying to use Entry
cause I wanted it to be generic (being able to update any Base
derived class) using Entry.OriginalValues
to avoid having to write a query myself. But now shit really hits the fan! Entry.OriginalValues
fails with an exception saying that DbSet<Derived>
doesn't exists. It's totally right, it doesn't. But it shouldn't as the the Derived
is mapped to DbSet<Base>
via inheritance.
Clearly I must be doing something wrong or something so different from everyone else as I'm unable to find anything useful on the matter. Haven't EF5 improved on this in anyway? Any suggestions on how I could approach this problem?
Firstly, I think an Update method is not necessary in the Repository since EF tracks changes and applies then when you call SaveChanges() on the context. Secondly, the problem might be that you're assigning a new collection to the Foos poperty when yo do: item.Foos = GenerateFoosWithBars(); You shouldn't do that since when EF materializes an object of the Derived type it actually returns a proxy which overrides the virtual Foos collection to use a special kind of lazy loaded collection that it tracks. If you assign a different collection of your own that will not be bound to the context. (I don't think that EF will handle that very well). What you should do is modify the collection items not the collection itself! Hope it helps!