首先使用EF 4.3代码更新实体

时间:2012-05-02 12:28:48

标签: .net database entity-framework

我有以下实体

public class Item
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Sections Sections { get; set; }
}

public class Section
{
    public int ID { get; set; }
    public string Name { get; set; }
}

public class Sections : List<Section>, ICollection<Section>
{ }

我添加了一个带有项目ID 1但没有任何部分的新项目......

现在我想要修改项目并在其中添加新部分,为此,我正在上下文中检索该项目并将其保存在另一个上下文中。在这里,我必须使用两个单独的上下文,因为不确定用户何时更新对象。在此之前我无法保持上下文对象的开放。

        Item fAp;
        using (var ctx = new MyContext())
        {
            fAp = ctx.Items.Include(a => a.Sections).Single(a => a.Id == 1);
        }

        using (var ctx2 = new MyContext())
        {
            var nsec = new Section()
            {
                ID = 1,
                Name = "App Sec...1"
            };

            fAp.Sections.Add(nsec);
            ctx2.Entry(fAp).State = EntityState.Modified;
            ctx2.SaveChanges();
        }

通过执行此操作,新部分未添加到数据库中。然后我在调用ctx2.SaveChanges()。

之前修改了代码并添加了以下行
            ctx2.Entry(nsec).State = EntityState.Added;

成功保存了。

现在,我的问题是我的数据层次结构非常复杂,我的意思是Section类也有很多子导航属性,那些属性也有很多,等等。

跟踪所有此类属性并手动设置其状态将非常困难。在这种情况下如何更新数据?

还有一件事,我不会使用急切加载,我的意思是我在检索Item对象时不会使用'Include'。我将在需要时使用显式加载,最后想要更新对象。

有什么最好的建议吗?

2 个答案:

答案 0 :(得分:0)

设置状态仅影响您传递给Entry调用的单个实体。一旦为数据持久性使用新的上下文实例,就必须始终告诉要保存的任何实体的EF状态。

在您的情况下,您需要执行以下任一操作:

ctx2.Items.Attach(fAp); // Now you informed context about existing entity
fAp.Sections.Add(nsec); // Now you told both context and your item that new section exists

或者这个(避免一些其他问题的首选解决方案):

fAp.Sections.Add(nsec); // Your item is not tracked by the new context yet
ctx2.Items.Add(fAp);     // Now context things that both item and section are new
ctx2.Entry(fAp).State = EntityState.Unchanged; // Make sure that item is not inserted again

或者这个:

fAp.Sections.Add(nsec); // Your item is not tracked by the new context yet
ctx2.Items.Attach(fAp); // Now context things that both item and section are existing
ctx2.Entry(nsec).State = EntityState.Added; // Make sure that section is tracked as new 
  

跟踪所有这些属性和设置将非常困难   他们手动的状态。在这种情况下如何更新数据?

您的代码正在进行这些更改,因此它不应该那么困难。您甚至可以向每个实体添加一些其他属性,如IsDirty,并将其用作帮助程序来跟踪实体的状态。

答案 1 :(得分:0)

更新实体

public class Item
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Sections Sections { get; set; }
    public OtherInfo Info { get; set; }
}
public class OtherInfo
{
    public Guid Id {get;set;}
    public string Description {get;set;}
}

在检索Item的对象后,用户可以修改任何内容。举个例子,用户只是插入一个新的Section,并通过传递对象Item来调用commit方法。

存储库类中的Commit方法

public void Commit(Item fAp)
{
    using (var ct = new MyContext())
    {
        bool isExist = ct.Item.Any(a => a.Id == fAp.Id);
        if (!isExist)
        {
           ct.Items.Add(fAp);
        }
        else
        {
           ct.Items.Attach(fAp);
           ct.Entry(fAp).State = EntityState.Modified;
        }
        ct.SaveChanges();
    }
}

在commit方法中,我不知道用户对该对象做了什么。在我的测试中,我添加了部分并调用此方法。由于,OtherInfo未被修改,因此抛出错误称为OtherInfo表的重复主键。

所以,为了使它工作,我必须改变所有实体的状态,如

  

部分 - 已添加; OtherInfo - NoChange;项目 - NoChange

由于结构有点复杂,因此很难跟踪所有实体。

这种方法(提交方法)是正确还是建议更好的解决方案?