Dot-Net

獲取對象的 DataContext

  • January 12, 2021

如果我有 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
}

如何獲取跟踪“客戶”對象更改的 DataContext 實例?

編輯:為什麼我不想將 DataContext 傳遞給方法。

  1. 始終傳遞 2 個對象而不是 1 個是整個應用程序的“醜陋”模式。
  • 每個業務對象的方法都需要下一個參數。
  • 收藏將需要從“列表”更改為“列表>”。

這兩點將更難維護 - 開發人員必須每次都設置正確的 DataContext 實例(容易創建錯誤),儘管 DataContext 知道具體對像是否附加到另一個 DataContext。

2)我想要(目前版本的應用程序使用它)處理來自不同“地方”的對象集合的“任何”業務邏輯(例如,通過拖放操作浮動視窗)。

Currentyl 我們使用自定義類型的數據集,因此有關更改的資訊位於數據行(DataRow = 業務對象)中,獲取它沒有問題,或者創建一個複製然後將其保存到數據庫中。

Kevin - 我感到你的痛苦……當你圍繞你的業務對象建構業務邏輯時,有時你只需要訪問對象所屬的 DataContext,因為不知道 DataContext 不得不放置你的程式碼在降低程式碼可維護性的地方。

我編寫了以下程式碼(恐怕是 VB),它提供了一個 Context 屬性,該屬性可以放置到數據對像上,然後用於返回該對象附加到的 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

這是一個 C# 版本:

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 已訂閱對象的 OnPropertyChanging 事件以監視對像生命週期內的更改這一事實。

如果這有幫助,請給這篇文章投票。

有關使用反射查找事件處理程序的更多資訊:

引用自:https://stackoverflow.com/questions/276531