使用实体框架DB第一种方法审核使用标识主键插入日志

时间:2014-01-10 11:22:04

标签: c# entity-framework dbcontext

我需要为表格创建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。这种方法甚至可能吗?如果没有,我的选择是什么?

提前致谢!

1 个答案:

答案 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