2008-11-09 79 views
9

如果我有LINQ對象:獲取對象的DataContext的

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的正確實例(很容易地創建一個bug),儘管在DataContext知道具體的對象(或沒有)連接到其他的DataContext 。

2)我希望(當前版本的應用程序使用它)處理來自不同「地點」(浮動窗口,例如拖放&)的對象集合的任何業務邏輯。

Currentyl我們使用自定義類型的DataSets,因此有關更改的信息位於數據行(DataRow =業務對象)中,並不是獲取它的問題,或者創建一個克隆然後將其保存到數據庫中。

+0

重新給我你的意見,你根本不應該使用這種方法:這意味着數據上下文是* *還長(因爲兩者隱式鏈接),但數據上下文通常應被視爲短期資源。 – 2008-11-10 06:56:36

+0

我修改了我們的需求和linq的功能,看起來linq-to-sql不是正確的方法,我們應該去。也許linq-to-entities可以提供所需的功能。 謝謝你的答案。 – TcKs 2008-11-10 11:04:19

回答

6

凱文 - 我感到你的痛苦......當你在業務對象周圍建立業務邏輯時,有時候你只需要就可以訪問對象所屬的DataContext,因爲不知道DataContext menas必須將代碼放在可減少代碼可維護性的地方。我寫了下面的代碼(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); 
} 

請務必小心,要注意的是對象只能找到它的DataContext的,如果它當前連接到上下文與ChangeTracking接通。此屬性依賴於DataContext已訂閱對象的OnPropertyChanging事件以監視對象使用期限內的更改的事實。

如果這是有幫助的,請對此貼發表投票。

欲瞭解更多信息使用反射來找到事件處理程序: http://weblogs.asp.net/avnerk/archive/2007/03/29/reflecting-over-an-event.aspx http://www.bobpowell.net/eventsubscribers.htm

2

最簡單的做法是將DataContext傳遞到您的方法中。

但是,您也可以考慮更改設計,以便遵循「單一方法應該只有一個目的」的規則,在這種情況下,您不希望以「保存」的方法與「修改」。

3

POCO的樂趣的一部分是,你不能確定對象知道誰跟蹤他。如果對象具有數據感知/延遲加載屬性,那麼您可以通過反射來跟蹤上下文,但實際上這可能會是一團糟。簡單地將數據上下文傳遞給需要它的代碼會更簡潔。

+0

我想在「整個」應用程序中使用我的對象。爲每個業務對象實例傳遞DataContext是不實際的:/。 – TcKs 2008-11-09 23:33:24