实体框架,问题更新相关对象 [英] Entity framework, problems updating related objects

查看:114
本文介绍了实体框架,问题更新相关对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用最新版本的实体框架的一个项目,我所遇到的我似乎无法来解决的问题。

当谈到更新现有的对象,我可以相当容易地更新对象属性确定,直到它是另一个类的引用属性。

在下面的例子中,我有一个名为Foo类,其中存储的各种属性,与其他班级的这些是实例2

 公共类Foo
{
     公众诠释标识{搞定;组;}
     公共字符串名称{;组;}
     公共SubFoo SubFoo {搞定;组}
     公共AnotherSubFoo AnotherSubFoo {搞定;组}
}

当我用下面的编辑方法,我传递的对象我想更新,我可以设法让名称正确更新,但我还没有设法找到在其中得到SubFoo的属性的方法改变。例如,如果SubFoo类有名称的属性,并且这已被改变,是我的DB和newFoo之间不同,它不进行更新。

 公共富编辑(富newFoo)
{        VAR dbFoo = context.Foo
                           .INCLUDE(X => x.SubFoo)
                           .INCLUDE(X => x.AnotherSubFoo)
                           。单(C => c.Id == newFoo.Id);        VAR进入= context.Entry<富>(dbFoo);
        entry.OriginalValues​​.SetValues​​(dbFoo);
        entry.CurrentValues​​.SetValues​​(newFoo);        context.SaveChanges();        返回newFoo;
}

任何帮助或指针将大大AP preciated。

更新:
基于Slauma评论我修改我的方法

 公共富编辑(富newFoo)
{        VAR dbFoo = context.Foo
                           .INCLUDE(X => x.SubFoo)
                           .INCLUDE(X => x.AnotherSubFoo)
                           。单(C => c.Id == newFoo.Id);        context.Entry(dbFoo).CurrentValues​​.SetValues​​(newFoo);
        context.Entry(dbFoo.SubFoo).CurrentValues​​.SetValues​​(newFoo.SubFoo);        context.SaveChanges();        返回newFoo;
}

在开始运行,我得到了错误


  

的实体类型Collection`1不是模型对当前的一部分
  上下文。


要避免这个搞定了,我加了code以尝试将newFoo子重视的背景下,但这种通过一个错误消息,说明的ObjectManager已经有了一个实体相同


  

具有相同键的对象已经存在于ObjectStateManager。
  该ObjectStateManager无法跟踪使用相同的多个对象
  关键



解决方案

CurrentValues​​.SetValues​​ 仅更新标量的属性,但没有相关的实体,所以你必须做对每个同相关实体:

 公共富编辑(富newFoo)
{
    VAR dbFoo = context.Foo
                       .INCLUDE(X => x.SubFoo)
                       .INCLUDE(X => x.AnotherSubFoo)
                       。单(C => c.Id == newFoo.Id);    context.Entry(dbFoo).CurrentValues​​.SetValues​​(newFoo);
    context.Entry(dbFoo.SubFoo).CurrentValues​​.SetValues​​(newFoo.SubFoo);
    context.Entry(dbFoo.AnotherSubFoo).CurrentValues​​.SetValues​​(newFoo.AnotherSubFoo);    context.SaveChanges();    返回newFoo;
}

如果关系可能已被完全删除或已经创造了你还需要明确处理这些情况:

 公共富编辑(富newFoo)
{
    VAR dbFoo = context.Foo
                       .INCLUDE(X => x.SubFoo)
                       .INCLUDE(X => x.AnotherSubFoo)
                       。单(C => c.Id == newFoo.Id);    context.Entry(dbFoo).CurrentValues​​.SetValues​​(newFoo);
    如果(dbFoo.SubFoo!= NULL)
    {
        如果(newFoo.SubFoo!= NULL)
        {
            如果(dbFoo.SubFoo.Id == newFoo.SubFoo.Id)
                //没有关系的变化,只标道具。
                context.Entry(dbFoo.SubFoo).CurrentValues​​.SetValues​​(newFoo.SubFoo);
            其他
            {
                //关系变化
                //附加假设newFoo.SubFoo是现有实体
                context.SubFoos.Attach(newFoo.SubFoo);
                dbFoo.SubFoo = newFoo.SubFoo;
            }
        }
        别的//关系已被删除
            dbFoo.SubFoo = NULL;
    }
    其他
    {
        如果(newFoo.SubFoo!= NULL)//关系已添加
        {
            //附加假设newFoo.SubFoo是现有实体
            context.SubFoos.Attach(newFoo.SubFoo);
            dbFoo.SubFoo = newFoo.SubFoo;
        }
        //别的 - >新老SubFoo为空 - >没事做
    }    //为AnotherSubFoo相同的逻辑......    context.SaveChanges();    返回newFoo;
}

您最终还需要设置附加实体到状态修改如果关系已更改的的标量性能以及。

修改

如果 - 根据您的评论 - Foo.SubFoo 实际上是一个集合而不是只是一个参考,你需要像这样来更新相关实体:

 公共富编辑(富newFoo)
{
    VAR dbFoo = context.Foo
                       .INCLUDE(X => x.SubFoo)
                       .INCLUDE(X => x.AnotherSubFoo)
                       。单(C => c.Id == newFoo.Id);    //更新富(仅适用于标量属性)
    context.Entry(dbFoo).CurrentValues​​.SetValues​​(newFoo);    //删除数据库不属于newFoo.SubFoo集合subFoos
    的foreach(在dbFoo.SubFoo.ToList变种dbSubFoo())
        如果(newFoo.SubFoo.Any(S =>!s.Id == dbSubFoo.Id))
            context.SubFoos.Remove(dbSubFoo);    的foreach(在newFoo.SubFoo VAR newSubFoo)
    {
        变种dbSubFoo = dbFoo.SubFoo.SingleOrDefault(S => s.Id == newSubFoo.Id);
        如果(dbSubFoo!= NULL)
            //更新subFoos属于newFoo.SubFoo集合
            context.Entry(dbSubFoo).CurrentValues​​.SetValues​​(newSubFoo);
        其他
            //插入subFoos到数据库中是不
            //将dbFoo.subFoo集合
            dbFoo.SubFoo.Add(newSubFoo);
    }    //与同为AnotherSubFoo ...    db.SaveChanges();    返回newFoo;
}

I am currently working on a project using the latest version of Entity Framework and I have come across an issue which I can not seem to solve.

When it comes to updating existing objects, I can fairly easily update the object properties ok, until it comes to a property which is a reference to another class.

In the below example I have a class called Foo, which stores various properties, with 2 of these being instances of other classes

public class Foo
{
     public int Id {get; set;}
     public string Name {get; set;}
     public SubFoo SubFoo {get; set}
     public AnotherSubFoo AnotherSubFoo {get; set}
}

When I use the below Edit method, I pass in the object I wish to update and I can manage to get the Name to properly update, however I have not managed to find a way in which to get the properties of the SubFoo to change. For example, if the SubFoo class has a property of Name, and this has been changed and is different between my DB and the newFoo, it does not get updated.

public Foo Edit(Foo newFoo)
{

        var dbFoo = context.Foo
                           .Include(x => x.SubFoo)
                           .Include(x => x.AnotherSubFoo)
                           .Single(c => c.Id == newFoo.Id);



        var entry = context.Entry<Foo>(dbFoo);
        entry.OriginalValues.SetValues(dbFoo);
        entry.CurrentValues.SetValues(newFoo);

        context.SaveChanges();

        return newFoo;
}

Any help or pointers would be greatly appreciated.

UPDATE: Based on the comment by Slauma I have modified my method to

public Foo Edit(Foo newFoo)
{

        var dbFoo = context.Foo
                           .Include(x => x.SubFoo)
                           .Include(x => x.AnotherSubFoo)
                           .Single(c => c.Id == newFoo.Id);



        context.Entry(dbFoo).CurrentValues.SetValues(newFoo);
        context.Entry(dbFoo.SubFoo).CurrentValues.SetValues(newFoo.SubFoo);

        context.SaveChanges();

        return newFoo;
}

When running this now, I get the error

The entity type Collection`1 is not part of the model for the current context.

To try and get around this, I added code to try to attach the newFoo subclasses to the context, but this through an error saying that the ObjectManager already had an entity the same

An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key

解决方案

CurrentValues.SetValues only updates scalar properties but no related entities, so you must do the same for each related entity:

public Foo Edit(Foo newFoo)
{
    var dbFoo = context.Foo
                       .Include(x => x.SubFoo)
                       .Include(x => x.AnotherSubFoo)
                       .Single(c => c.Id == newFoo.Id);

    context.Entry(dbFoo).CurrentValues.SetValues(newFoo);
    context.Entry(dbFoo.SubFoo).CurrentValues.SetValues(newFoo.SubFoo);
    context.Entry(dbFoo.AnotherSubFoo).CurrentValues.SetValues(newFoo.AnotherSubFoo);

    context.SaveChanges();

    return newFoo;
}

If the relationship could have been removed altogether or have been created you also need to handle those cases explicitly:

public Foo Edit(Foo newFoo)
{
    var dbFoo = context.Foo
                       .Include(x => x.SubFoo)
                       .Include(x => x.AnotherSubFoo)
                       .Single(c => c.Id == newFoo.Id);

    context.Entry(dbFoo).CurrentValues.SetValues(newFoo);
    if (dbFoo.SubFoo != null)
    {
        if (newFoo.SubFoo != null)
        {
            if (dbFoo.SubFoo.Id == newFoo.SubFoo.Id)
                // no relationship change, only scalar prop.
                context.Entry(dbFoo.SubFoo).CurrentValues.SetValues(newFoo.SubFoo);
            else
            {
                // Relationship change
                // Attach assumes that newFoo.SubFoo is an existing entity
                context.SubFoos.Attach(newFoo.SubFoo);
                dbFoo.SubFoo = newFoo.SubFoo;
            }
        }
        else // relationship has been removed
            dbFoo.SubFoo = null;
    }
    else
    {
        if (newFoo.SubFoo != null) // relationship has been added
        {
            // Attach assumes that newFoo.SubFoo is an existing entity
            context.SubFoos.Attach(newFoo.SubFoo);
            dbFoo.SubFoo = newFoo.SubFoo;
        }
        // else -> old and new SubFoo is null -> nothing to do
    }

    // the same logic for AnotherSubFoo ...

    context.SaveChanges();

    return newFoo;
}

You eventually also need to set the state of the attached entities to Modified if the relationship has been changed and the scalar properties as well.

Edit

If - according to your comment - Foo.SubFoo is actually a collection and not only a reference you will need something like this to update the related entities:

public Foo Edit(Foo newFoo)
{
    var dbFoo = context.Foo
                       .Include(x => x.SubFoo)
                       .Include(x => x.AnotherSubFoo)
                       .Single(c => c.Id == newFoo.Id);

    // Update foo (works only for scalar properties)
    context.Entry(dbFoo).CurrentValues.SetValues(newFoo);

    // Delete subFoos from database that are not in the newFoo.SubFoo collection
    foreach (var dbSubFoo in dbFoo.SubFoo.ToList())
        if (!newFoo.SubFoo.Any(s => s.Id == dbSubFoo.Id))
            context.SubFoos.Remove(dbSubFoo);

    foreach (var newSubFoo in newFoo.SubFoo)
    {
        var dbSubFoo = dbFoo.SubFoo.SingleOrDefault(s => s.Id == newSubFoo.Id);
        if (dbSubFoo != null)
            // Update subFoos that are in the newFoo.SubFoo collection
            context.Entry(dbSubFoo).CurrentValues.SetValues(newSubFoo);
        else
            // Insert subFoos into the database that are not
            // in the dbFoo.subFoo collection
            dbFoo.SubFoo.Add(newSubFoo);
    }

    // and the same for AnotherSubFoo...

    db.SaveChanges();

    return newFoo;
}

这篇关于实体框架,问题更新相关对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆