【问题标题】:What's the cleanest way to make a Linq object "dirty"?使 Linq 对象“脏”的最干净的方法是什么?
【发布时间】:2009-08-24 09:07:00
【问题描述】:

我有一个 MyClass 类型的 Linq-To-SQL 对象 obj,我通过我的数据上下文加载了该对象。

现在我想强制保存该对象,即使没有实际更改任何字段,以便保存操作可以在幕后触发一些触发器。

让我的数据上下文认为obj 是脏的,以便调用SubmitChanges() 将导致obj 被保存的最简单方法是什么?

【问题讨论】:

  • 从 dc 调用 Table 上的 Attach(obj, true) 怎么样?
  • @meandmycode .Attach(obj, true) 在某些情况下会起作用,但如果:a) 对象已附加到数据上下文或 b) 对象已分离但没有版本,则不会成员(时间戳/行版本)

标签: c# linq linq-to-sql


【解决方案1】:

只需将属性更改为虚拟值,然后返回...

var value = obj.SomeField;
obj.SomeField = "dummy";
obj.SomeField = value;
dc.SubmitChanges();

编辑:让我收回。 L2S 更改跟踪器不会被此愚弄。如果您不想更改任何现有列,最简单/最干净/最安全的方法可能是添加一个新列并进行更改。

如果您绝对不能进行任何数据库更改(即添加新列),那么使用反射访问更改跟踪器可能是一种选择。我还没有尝试过,但看起来通往那的路线(大致):

1) 数据上下文有一个名为 services 的私有成员。
2) services 指向一个 CommonDataServices,它有一个私有成员跟踪器和一个内部成员 ChangeTracker(返回前者)。
3) 变更跟踪器有一个 GetTrackedObject 内部方法,该方法返回一个 TrackedObject。
4) TrackedObject 有一个 ConvertToModified 方法...

编辑#2:我刚刚测试了上面的反射路径,它似乎可以工作。例如:

            using (advWorksDataContext dc = new advWorksDataContext())
        {
            Employees emp = dc.Employees.FirstOrDefault();
            dc.MakeDirty(emp);
            dc.SubmitChanges();
        }

...MakeDirty 的实现是:

public static class DCExtensions
{
    internal static void MakeDirty(this System.Data.Linq.DataContext dc, object someEntity)
    {
        //get dc type
        Type dcType = dc.GetType();
        while (dcType != typeof(System.Data.Linq.DataContext))
        {
            dcType = dcType.BaseType;
        }  

        //get hold of the CommonDataServices thing in the DC
        System.Reflection.FieldInfo commonDataServicesField 
            = dcType.GetField("services", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
        object commonDataServices = commonDataServicesField.GetValue(dc);
        Type commonDataServicesType = commonDataServices.GetType();  

        //get hold of the change tracker
        System.Reflection.PropertyInfo changeTrackerProperty 
            = commonDataServicesType.GetProperty("ChangeTracker", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
        object changeTracker = changeTrackerProperty.GetValue(commonDataServices, null);
        Type changeTrackerType = changeTracker.GetType();  

        //get the tracked object method
        System.Reflection.MethodInfo getTrackedObjectMethod
            = changeTrackerType.GetMethod("GetTrackedObject", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
        object trackedObject = getTrackedObjectMethod.Invoke(changeTracker, new object[] { someEntity } );  

        //get the ConvertToModified method
        Type trackedObjectType = trackedObject.GetType();
        System.Reflection.MethodInfo convertToModifiedMethod
            = trackedObjectType.GetMethod("ConvertToModified", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);  

        //call the convert to modified method
        convertToModifiedMethod.Invoke(trackedObject, null);
    }
}

【讨论】:

  • 啊,我想知道这个想法。 Linq 是否通过调用任何属性的“Set”方法或通过比较加载值与当前值来确定脏度?从你说的情况来看,是前者。
  • 啊哈。我也发现了这一点。可惜,这对我来说是最容易的。我不太喜欢攻击数据上下文的私人成员的所有这些黑暗艺术……似乎有点危险。所以我想这对我来说毕竟是“肮脏”的领域。谢谢!
【解决方案2】:

如果这不会破坏其他任何东西,您可以尝试 2 次提交吗?因此,您可以使用 Kristofer 的第一个答案的变体:

Just change a property to a dummy value, save it, and then change back...
var value = obj.SomeField;
obj.SomeField = "dummy";
dc.SubmitChanges();
obj.SomeField = value;
dc.SubmitChanges();

对你的目的有什么好处吗?

【讨论】:

  • 同意,但如果他无法向 db 添加任何其他列,则可行
猜你喜欢
  • 2020-06-28
  • 2019-12-19
  • 2014-05-03
  • 1970-01-01
  • 2011-12-02
  • 2021-04-14
  • 1970-01-01
  • 2019-11-28
  • 1970-01-01
相关资源
最近更新 更多