代码之家  ›  专栏  ›  技术社区  ›  TcKs

获取对象的DataContext

  •  9
  • TcKs  · 技术社区  · 18 年前

    如果我有LINQ对象:

    public class SampleDataContext : DataContext {
        public Table<Customer> Customers { get { return this.GetTable<Customer>(); } }
        public SampleDataContext( string connectionString ) : base( connectionString ) { }
    }
    
    [Table( Name="dbo.tblCustomers" )]
    public class Customer {
        private Guid? customerID;
        [Column( Storage="customerID", DbType="uniqueidentifier NOT NULL", IsPrimaryKey=true )]
        public Guid? CustomerID {
            get { return this.customerID; }
            set { this.customerID = value; }
        }
    
        private string customerName;
        [Column( Storage = "customerName", DbType = "nvarchar(255) NOT NULL" )]
        public string CustomerName {
            get { return this.customerName; }
            set { this.customerName = value; }
        }
    }
    

    public static void DoSomethingWithCustomer( Customer customer ) {
        // some operations
        // now, I want save changes to the database
    }
    

    如何获取跟踪“customer”对象更改的DataContext实例?

    1) 始终传递2个对象而不是1个对象对于整个应用程序来说是“丑陋”的模式。

    • 集合将需要从“列表”更改为“列表”。

    2) 我希望(当前版本的应用程序使用it)处理来自不同“位置”的对象集合上的“任何”业务逻辑(例如,通过拖放操作的浮动窗口)。

    Currentyl我们使用自定义类型的数据集,因此有关更改的信息位于数据行(DataRow=business object)中,获取它或创建克隆然后将其保存到数据库中并不成问题。

    3 回复  |  直到 18 年前
        1
  •  6
  •   Andrew Morton    5 年前

    凯文-我感觉到你的痛苦。。。当您围绕业务对象构建业务逻辑时,有时您只需 有

    我编写了以下代码(恐怕是VB),它提供了一个可以放置在数据对象上的上下文属性,然后用于返回对象所附加的DataContext(如果有的话)。

    Private Const StandardChangeTrackerName As String = "System.Data.Linq.ChangeTracker+StandardChangeTracker"
    
    Private _context As DataClasses1DataContext
    Public Property Context() As DataClasses1DataContext
        Get
            Dim hasContext As Boolean = False
            Dim myType As Type = Me.GetType()
            Dim propertyChangingField As FieldInfo = myType.GetField("PropertyChangingEvent", BindingFlags.NonPublic Or BindingFlags.Instance)
            Dim propertyChangingDelegate As PropertyChangingEventHandler = propertyChangingField.GetValue(Me)
            Dim delegateType As Type = Nothing
    
            For Each thisDelegate In propertyChangingDelegate.GetInvocationList()
                delegateType = thisDelegate.Target.GetType()
                If delegateType.FullName.Equals(StandardChangeTrackerName) Then
                    propertyChangingDelegate = thisDelegate
                    hasContext = True
                    Exit For
                End If
            Next
    
            If hasContext Then
                Dim targetField = propertyChangingDelegate.Target
                Dim servicesField As FieldInfo = targetField.GetType().GetField("services", BindingFlags.NonPublic Or BindingFlags.Instance)
                If servicesField IsNot Nothing Then
    
                    Dim servicesObject = servicesField.GetValue(targetField)
    
                    Dim contextField As FieldInfo = servicesObject.GetType.GetField("context", BindingFlags.NonPublic Or BindingFlags.Instance)
    
                    _context = contextField.GetValue(servicesObject)
    
                End If
            End If
        
            Return _context
        End Get
        Set(ByVal value As DataClasses1DataContext)
    
            _context = value
    
        End Set
    
    End Property
    

    public DataContext GetMyDataContext()
    {
        // Find the StandardChangeTracker listening to property changes on this object.
        // If no StandardChangeTracker is listening, then this object is probably not
        // attached to a data context.
        var eventField = this.GetType().GetField("PropertyChangingEvent", BindingFlags.NonPublic | BindingFlags.Instance);
        var eventDelegate = eventField.GetValue(this) as Delegate;
        if (eventDelegate == null)
            return null;
        eventDelegate = eventDelegate.GetInvocationList().FirstOrDefault(
            del => del.Target.GetType().FullName == "System.Data.Linq.ChangeTracker+StandardChangeTracker");
        if (eventDelegate == null)
            return null;
    
        // Dig through the objects to get the underlying DataContext.
        // If the following fails, then there was most likely an internal change
        // to the LINQ-to-SQL framework classes.
        var targetField = eventDelegate.Target;
        var servicesField = targetField.GetType().GetField("services", BindingFlags.NonPublic | BindingFlags.Instance);
        var servicesObject = servicesField.GetValue(targetField);
        var contextField = servicesObject.GetType().GetField("context", BindingFlags.NonPublic | BindingFlags.Instance);
        return (DataContext)contextField.GetValue(servicesObject);
    }
    

    请注意,如果对象当前连接到打开了ChangeTracking的上下文,则该对象只能定位其DataContext。此属性依赖于DataContext已订阅对象的OnPropertyChange事件以监视对象生命周期内的更改这一事实。

    如果这有帮助,请在这篇文章上投票。

    有关使用反射查找事件处理程序的详细信息:

        2
  •  3
  •   Marc Gravell    18 年前

    POCO 知道 谁在跟踪他。如果对象具有数据感知/延迟加载属性,则 能够通过反射追踪上下文,但实际上这将是一个混乱。简单地将数据上下文传递给需要它的代码将更为简洁。

        3
  •  2
  •   Wayne Bloss    18 年前

    最简单的方法是将DataContext传递到方法中。

    但是,您也可以考虑更改设计,以便遵循“单个方法只具有一个目的”的规则,在这种情况下,您不希望在“修改”相同的方法中“保存”。

    推荐文章