SQL 2005数据库设计和实体框架事务难题

时间:2009-11-25 04:34:59

标签: entity-framework schema

我有一个数据库设计问题,我试图也适合Entity Framework。它的复杂性,我继承了它,为时已晚,无法做出重大改变!在做出如何前进的决定之前,我想借鉴其他人的智慧...我原来的帖子要长得多,但我认为业务逻辑细节可能并不重要。

所以简单地说明问题,比如我在同一个数据库中有两个表:

表A

标识, (其他栏目......)

表B

标识, TableId(< ---软键), TableTypeId, (其他栏目......)

现在TableB对表A有一个“软键”,通常可以是外键,但是我所拥有的架构不是,并且相信我它不可能(原因是“假外国”关键点“指向76个不同表中的任何一个,具体取决于TableB的”TableTypeId“列中的内容。)

现在,我们正在使用Entity Framework。显然,两个表之间不能有导航属性。问题是我需要在单个事务中处理这两个表。例如,当我向TableA添加记录时,我还需要向TableB添加一条记录,并使用TableA中为TableB的“TableId”列创建的新Identity值。

使用Navigation属性,我可以在内存中连接两个EntityObjects,然后调用Context.SaveChanges()和EntityFramework在事务中完成所有操作。但是,如果没有导航属性,我必须先插入TableA,获取Identity,然后使用第一个插入的结果插入TableB。这是两笔交易......

我听说Entity Framework允许您在更复杂的情况下处理更多事务,例如定义自己的事务范围和使用其他参数到COntext.SaveChanges()。然而,在我尝试这个之前,我想知道我的问题是否可以在一次交易中解决......

除了架构重新设计之外,我还有哪些选项......

由于

1 个答案:

答案 0 :(得分:0)

...哎哟

在EF 4.0中,您可以覆盖保存更改方法,手动启动事务,将TableB模型设置为未更改,保存表A,AcceptAllChanges(),将TableB标记为已更改,然后保存TableB。

对于EF1,您必须手动启动环境事务(使用var scope = new TransactionScope){},然后执行相同的过程。将TableA添加到您的上下文中,如果已添加标记TableB为未更改,则调用SaveChanges(希望仅保存您的TableA对象),调用AcceptAllChanges(),将TableB更新为已更改并添加软键值,再次调用SaveChanges。完成交易。

AcceptAllChanges()或ChangeObjectState()是你的朋友:

http://msdn.microsoft.com/en-us/library/system.data.objects.objectstatemanager.changeobjectstate(VS.100).aspx

http://msdn.microsoft.com/en-us/library/system.data.objects.objectcontext.acceptallchanges(VS.100).aspx

在这两种情况下,必须告诉EF忽略TableB,保存TableA,然后在环境事务中再次关注TableB。这是100%可能的(我会做类似的事情)它只需要一些工作。

伪代码:

  using (TransactionScope transaction = new TransactionScope())
  {
        //Set TableB as unchanged so EF ignores it
      YourObjectContext.ObjectStateManager.ChangeObjectState(TableBObject,EntityState.Unchanged);

      YourObjectContext.SaveChanges();
      YourObjectContext.AcceptAllChanges();

      TableB.SoftFK = TableA.Fk;          

      YourObjectContext.ObjectStateManager.ChangeObjectState(TableBObject,EntityState.Modified);

      YourObjectContext.SaveChanges();
      YourObjectContext.AcceptAllChanges();

      Transaction.Complete();
  }