我有两张桌子,HOTEL和OWNER。 两者都有和Identity列,但是其中一个具有另一个表所需的外键。
我需要同时以事务方式添加两个记录,但如果主表上的插入失败,我需要回滚写入辅助表记录的事务。
据我所知,我需要.SaveChanges()从辅助表中获取自动生成的ID,但这似乎也是在提交事务。
还有其他办法吗?
public class HOTEL
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Int64 HOTEL_ID { get; set; }
public string blah1 { get; set; }
public string blah2 { get; set; }
}
public class OWNER
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Int64 OWNER_ID { get; set; }
public string blah3 { get; set; }
public string blah4 { get; set; }
public Int64 HOTEL_ID { get; set; }
[ForeignKey("HOTEL_ID")]
public virtual HOTEL HOTEL { get; set; }
}
...
public class MyContext : DbContext
{
public MyContext() : base() { }
public MyContext(string connectionString) : base(connectionString) { }
public DbSet<HOTEL> HOTELs { get; set; }
public DbSet<OWNER> OWNERs { get; set; }
public ObjectContext ObjectContext
{
get
{
return (this as IObjectContextAdapter).ObjectContext;
}
}
}
...
Int64 ret = 0;
// Suppress required for DB2.
using (var transaction = new TransactionScope(TransactionScopeOption.Suppress))
{
try
{
using (var context = new MyContext())
{
var secondaryEntity = new HOTEL();
context.HOTELs.Add(secondaryEntity);
// This appears to commit the changes in the trasaction.
context.SaveChanges();
primaryEntity.HOTEL_ID = secondaryEntity.HOTEL_ID;
context.OWNERs.Attach(primaryEntity);
context.Entry(primaryEntity).State = primaryEntity.OWNER_ID == 0 ? EntityState.Added : EntityState.Modified;
context.SaveChanges();
ret = primaryEntity.OWNER_ID;
}
}
catch (Exception ex)
{
// Deal with errors.
}
if (ret != 0)
{
transaction.Complete();
}
}
return ret;
答案 0 :(得分:0)
在完成这个工作之后,事实证明真正的问题是因为我使用的是TransactionScopeOption.Suppress。 我正在使用它,因为看起来DB2没有使用任何其他选项。这是因为我使用的是Client 9.7 Fixpack 4。 使用任何其他TransactionScopeOption时,它返回以下错误。
ERROR [57016] [IBM][DB2/NT64] SQL0668N Operation not allowed for reason code "7" on table "DB2ADMIN.HOTEL".
深入研究,这是因为DB2没有参与TransactionScope。 在查看了这个问题上的其他一些问题之后,通过以下步骤解决了这个问题。
如果我继续使用DB2 9.7 FP4,我需要在注册表项HKLM \ SOFTWARE \ Microsoft \ MSDTC \ XADLL下输入一个名为“DB2CLI.DLL”且值为“C:\ Program Files”的值IBM \ SQLLIB \ BIN \ DB2CLI.DLL'
[HKEY_LOCAL_MACHINE \ SOFTWARE \微软\ MSDTC \ XADLL] “DB2CLI.DLL”=“C:\ Program Files \ IBM \ SQLLIB \ BIN \ db2cli.dll”
或者(从注册表项中),至少安装DB2 Client 9.7 FP6。
最终的代码就像这样。
Int64 ret = 0;
using (var transaction = new TransactionScope(TransactionScopeOption.Required))
{
try
{
using (var context = new MyContext())
{
var secondaryEntity = new HOTEL();
context.HOTELs.Add(secondaryEntity);
// SaveChanges(bool) has been depricated, use SaveOptions.
// SaveChanges is required to generate the autogenerated Identity HOTEL_ID.
context.ObjectContext.SaveChanges(SaveOptions.AcceptAllChangesAfterSave);
primaryEntity.HOTEL_ID = secondaryEntity.HOTEL_ID;
context.OWNERs.Attach(primaryEntity);
context.Entry(primaryEntity).State = primaryEntity.OWNER_ID == 0 ? EntityState.Added : EntityState.Modified;
context.ObjectContext.SaveChanges(SaveOptions.AcceptAllChangesAfterSave);
ret = primaryEntity.OWNER_ID;
if (ret != 0)
{
transaction.Complete();
context.ObjectContext.AcceptAllChanges();
}
}
}
catch (Exception ex)
{
// Deal with errors.
}
}
return ret;
从@Pawel读取注释后的替代方法,它将生成secondaryEntity的ID并自动将其附加到primaryEntity,而无需手动分配值:
Int64 ret = 0;
using (var transaction = new TransactionScope(TransactionScopeOption.Required))
{
try
{
using (var context = new MyContext())
{
var secondaryEntity = new HOTEL();
primaryEntity.HOTEL = secondaryEntity;
context.HOTELs.Add(secondaryEntity);
context.OWNERs.Attach(primaryEntity);
context.Entry(primaryEntity).State = primaryEntity.OWNER_ID == 0 ? EntityState.Added : EntityState.Modified;
context.SaveChanges();
ret = primaryEntity.OWNER_ID;
// TransactionScopeOption.Required can still used in case something
// goes wrong with additional processing at this point.
if (ret != 0)
{
transaction.Complete();
}
}
}
catch (Exception ex)
{
// Deal with errors.
}
}
return ret;