2008-11-09 81 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