2012-05-02 141 views
0

我有以下实体更新使用EF 4.3代码第一

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> 
{ } 

我添加了一个项目编号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'。我将在需要时使用显式加载,并最终要更新对象。

任何最佳建议?

回答

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,并将其用作帮助程序来跟踪实体的状态。

+0

谢谢@Ladislav 我不会有任何控制客户端如何更新我的对象。我已经创建了存储库,客户请求该项目。然后再次调用commit方法。 – Hitesh

+0

由于这里有一个空间限制,我已经在下面详细回复了... – Hitesh

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;} 
} 

项目的检索对象后,用户可以修改任何东西。比如上面给出的例子,用户只是插入一个新的Section,并通过传递Object Item来调用commit方法。

提交的repository类

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(); 
    } 
} 

以下方法提交方法,我不知道什么用户使用这个对象。在我的测试中,我添加了部分并调用此方法。因为,OtherInfo没有被修改,所以它的抛出错误说明了OtherInfo表的重复主键。

因此,为了使其工作,我不得不改变所有实体的一样

科的地位 - 增加; OtherInfo - NoChange; Item - NoChange

由于结构有点复杂,看起来很难追踪所有实体。

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