Linq to SQL:在更新到另一个实体期间动态插入

时间:2012-08-13 14:21:48

标签: c# linq-to-sql

我正在使用Linq to SQL,并且我想在每次更新特定记录时插入表格。

我们假设Table1Table2,只要Table1中的记录更新,我就想在Table2中插入新记录。

目前我有工作代码,允许我在Table1更新时更新几个字段,这是通过为UpdateTable1函数创建部分方法来实现的,如下所示: / p>

partial void UpdateTable1(Table1 instance)
{
   //update some fields
   this.ExecuteDynamicUpdate(instance);
}

这非常有用,非常有用,我想用它来确保在更新Table2时始终在Table1中创建新记录。这主要是为了记录目的。

这就是我下次尝试做的事情:

partial void UpdateTable1(Table1 instance)
{
   //update some fields
   this.ExecuteDynamicUpdate(instance);
   this.ExecuteDynamicInsert(instance.ConvertToTable2());
}

(我在这里使用扩展方法创建基于Table1实例的Table2记录)

问题是我收到以下错误:

  

无法对实体执行操作,因为实际操作不是   正在改变跟踪。

任何想法如何使我的工作?

2 个答案:

答案 0 :(得分:3)

忘记我不可靠的解决方法(如果必须,请参阅编辑历史),我找到了一种更可靠的方法来完成这项工作!

首先,忘记为此使用部分方法(例如问题中的UpdateTable1),除非您仅修改实例记录的数据,否则这种方法效果不佳。所以我只保留这些部分方法,因为我需要更新实例中的相关字段。

执行此操作的方法是覆盖部分SubmitChanges类中的DataContext方法。这将允许在允许默认SubmitChanges处理之前插入/更新/删除任何表记录(从而锁定此功能)。

在覆盖中,您可以使用DataContext访问当前的this.GetChangeSet()更改集,您可以循环所有更改并执行所需的任何其他表工作(例如添加日志记录)。

对于下面的示例,假设我有一个名为Table1的标准数据库表,并且我有一个名为Table1Log的匹配日志表,我想记录对Table1内所做的任何更改Table1Log,因此日志表包含与原始字段相同的所有字段,但扩展它以存储DateTime(更改时间)和LogType(即添加/编辑/删除)。

以下是我最终代码的重要部分:

partial class MyDataContext
{

    public override void SubmitChanges(System.Data.Linq.ConflictMode failureMode)
    {

        var set = this.GetChangeSet();//get a list of all pending changes

        foreach (var item in set.Inserts)
        {
            AddLog(item, LogType.Add);
        }
        foreach (var item in set.Updates)
        {
            AddLog(item, LogType.Edit);
        }
        foreach (var item in set.Deletes)
        {
            AddLog(item, LogType.Delete);
        }

        base.SubmitChanges(failureMode);//allow the DataContext to perform it's default work (including your new log changes)

    }

    public void AddLog(object item, LogType logType)
    {

        //some painful type testing, so feel free to refactor this as you wish
        if(item is Table1)
        {
           var log = (item as Table1).ToLog(logType);//ToLog() is an extension method (one for each type)
           this.Table1_Logs.InsertOnSubmit(log);//add the log record ready to be submitted
        }
        else if(item is Table2)
        {
           //same again
        }
        //...repeat for each table class type

    }

}

注意:if / else类型测试的替代方法可以是found here。我实际上在我的代码中使用了它并且它非常好用,我怀疑它有性能优势但是当你需要切换50多种类型时它确实有助于使事情更具可读性。

答案 1 :(得分:0)

好吧,对于插入,你真的只有两个选择。好吧,实际上是3个。

您可以向数据库添加触发器。我们将其用于我工作的变更跟踪。我们有一个更新触发器,可以插入包含更改的记录。这很有效,也很容易。

如果您想使用LINQ to SQL,您唯一的选择是按照您指定的方式插入表格,即db.Table2s.InsertOnSubmit(...),然后提交更改。

另一个选项,假设您的日志表与实体之间存在外键关系,则通过LINQ to SQL分配该实体关系,然后您只需插入日志实体,而无需引用数据上下文。 / p>

partial void UpdateEntity(Entity instance)
{
    instance.Logs.Add(instance.createLogEntry());
}

以这种方式完成后,您不需要引用数据上下文,但根据您的情况,这可能不是一个选项。