我需要为表格创建CRUD函数的“审计跟踪”,但是当涉及解决方案的Insert部分时我很困惑:
问题在于Audit
表需要编辑行的ID
,但是正在编辑的表的ID是IDENTITY
,更糟糕的是,{{ 1}}表用于审计多个表,因此无法使用外键。
我已经创建了代码和表格的简化版本:
表:
Audit
代码:
CREATE TABLE Audit
(
ID BIGINT NOT NULL PRIMARY KEY IDENTITY,
TableName VARCHAR(100) NOT NULL,
InsertedID BIGINT NOT NULL, --This is the ID of the row which has been inserted
DateTimeInserted DATETIME NOT NULL
)
CREATE TABLE Customer
(
ID BIGINT NOT NULL PRIMARY KEY IDENTITY,
Name VARCHAR(100),
Surname VARCHAR(100)
)
现在通常我会先采用提交模型的插入方法,调用class Program
{
static void Main(string[] args)
{
Customer customer = new Customer()
{
Name = "Foo",
Surname = "Bar"
};
using (SampleAuditEntities dbContext = new SampleAuditEntities())
{
InsertAuditTool insertAuditTool = new InsertAuditTool(dbContext);
insertAuditTool.TestInsert(customer);
dbContext.SaveChanges();
}
Console.WriteLine("Customer ID = " + customer.ID);
Console.ReadLine();
}
}
class InsertAuditTool
{
SampleAuditEntities dbContext;
public InsertAuditTool(SampleAuditEntities DbContext)
{
this.dbContext = DbContext;
}
public void TestInsert(Customer InsertedCustomer)
{
Audit audit = new Audit()
{
TableName = "Customer",
DateTimeInserted = DateTime.Now,
InsertedID = InsertedCustomer.ID //Always 0 as it is not assigned until the change is committed.
};
dbContext.Customers.Add(InsertedCustomer);
dbContext.Audits.Add(audit);
}
}
然后插入审计表,但是可能允许提交插入并进行审计是不好的做法失败,因为必须审核每个插入(反之亦然)。
所以我的问题是,如何在没有2个单独的事务的情况下准确记录Inserted行的新ID。这种方法甚至可能吗?如果没有,我的选择是什么?
提前致谢!
答案 0 :(得分:0)
所以(通常)只有在发布此问题并使用不同的术语执行更多“Google搜索”之后,我才能找到Stack Overflow上类似问题的答案。
EF Code First DBContext and Transactions
回答者建议使用对我来说效果很好的TransactionScope。这让我想到了以下解决方案:
注意:我必须向System.Transactions
添加引用和using语句代码:
using System;
using System.Text;
using System.Transactions;
namespace RefSandBoc
{
class Program
{
static void Main(string[] args)
{
try
{
Customer customer = new Customer()
{
Name = "Foo",
Surname = "Bar"
};
using (SampleAuditEntities dbContext = new SampleAuditEntities())
{
using (var scope = new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }))
{
InsertAuditTool insertAuditTool = new InsertAuditTool(dbContext);
insertAuditTool.TestInsert(customer);
//throw new Exception("Test Exception");
scope.Complete();
}
}
Console.WriteLine("Customer ID = " + customer.ID);
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
}
}
class InsertAuditTool
{
SampleAuditEntities dbContext;
public InsertAuditTool(SampleAuditEntities DbContext)
{
this.dbContext = DbContext;
}
public void TestInsert(Customer InsertedCustomer)
{
dbContext.Customers.Add(InsertedCustomer);
dbContext.SaveChanges();
//throw new Exception("Test Exception");
Audit audit = new Audit()
{
DateTimeInserted = DateTime.Now,
InsertedID = InsertedCustomer.ID
};
dbContext.Audits.Add(audit);
dbContext.SaveChanges();
//throw new Exception("Test Exception");
}
}
}
如果我取消注释任何一个例外,代码的行为就像我期望的那样。这种方法的唯一缺点是,一旦调用TransactionScope.Complete()方法,无论DBContext中是否存在其他并发事务,都将提交更改。
为了进一步学习,还有一篇关于Code Project的优秀文章详细介绍了TransactionScope的使用:http://www.codeproject.com/Articles/690136/All-About-TransactionScope