Cleanly updating a hierarchy in Entity Framework

此生再无相见时 提交于 2019-11-28 07:53:38

It is not that hard. There are 2 main ways to work using EF: Attached entities and Detached entities.

Let's suppose that we have 2 entites:

public class Foo
{
     public int FooId { get; set; }

     public string Description { get; set; }

     public ICollection<Bar> Bars { get; set; }
 }

public class Bar
{
    public int BarId { get; set; }

    public string Description { get; set; }
}

INSERTING

var foo = new Foo()
{
    FooId = 1,
    Description = "as",
    Bars = new List<Bar>()
    {
        new Bar
        {
            BarId = 1,
            Description = "as"
        },
        new Bar
        {
            BarId = 2,
            Description = "as"
        },
        new Bar
        {
            BarId = 2,
            Description = "as"
        }
    }
};

ctx.Foos.Add(foo);
ctx.SaveChanges();

In the above example, EF will recognize the new items, and will insert all of them.

UPDATING (ATTACHED)

var foo = ctx.Foos.Include("Bars").Where(i => i.FooId == 1).FirstOrDefault();
foreach (var bar in foo.Bars)
{
    bar.Description = "changed";
}

ctx.SaveChanges();

Here we loaded foo and its bars from the context. They are already attached to the context. So, all we need to do is change the values and call SaveChanges(). Everything will work fine.

UPDATING (DETACHED)

var foo = new Foo
{
    FooId = 1,
    Description = "changed3",
    Bars = new List<Bar>
    {
        new Bar
        {
            BarId = 1,
            Description = "changed3"
        },
        new Bar
        {
            BarId = 2,
            Description = "changed3"
        }
    }
};

ctx.Entry(foo).State = EntityState.Modified;

foreach (var bar in foo.Bars)
{
    ctx.Entry(bar).State = EntityState.Modified;
}

ctx.SaveChanges();

Here, we are working with items which already exists in database. However, they were not loaded from EF (they are not attached). EF knows nothing about them. We need to attached all of them manually and tell EF that they are modified.

REMOVING (ATTACHED)

var foo = ctx.Foos.Include("Bars").Where(i => i.FooId == 1).FirstOrDefault();
var bar = foo.Bars.First();
foo.Bars.Remove(bar);
ctx.SaveChanges();

Load bars from EF and just remove them from the collection.

REMOVING (DETACHED)

var bar = new Bar
{
    BarId = 1
};

ctx.Entry(bar).State = EntityState.Deleted;
ctx.SaveChanges();

Here, Bar was not loaded from the context. So, we have to tell EF that it is deleted.


In your case, you are sending the updated object to an MVC Controller; so, you have to tell EF that StoredProcedureReport and StoredProcedureParameters are modified.

If all the properties are being modified you can use:

ctx.Entry(foo).State = EntityState.Modified;
//remember to do the same in all children objects

It will mark all properties as modified. Be aware that if some property was not set on view, it will be updated as an empty value.

If not all the properties are being modified, you have to specify which properties are. Like this:

context.Entry(foo).Property("Description").IsModified = true; 
context.Entry(foo).Property("AnotherProperty").IsModified = true; 

Hope it helps!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!