如果我有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实例(很容易创建一个bug),尽管DataContext知道具体对象是(或没有)附加到另一个DataContext。
2)我想(当前版本的应用程序使用它)处理来自不同“地方”的对象集合的“任何”业务逻辑(例如通过拖放的浮动窗口)。
Currentyl我们使用自定义类型的DataSet,因此有关更改的信息在数据行(DataRow =业务对象)中,并且获取它没有问题,或创建克隆然后将其保存到数据库中。
答案 0 :(得分:6)
凯文 - 我感到很痛苦......当你围绕业务对象构建业务逻辑时,有时你只是拥有来访问对象所属的DataContext,因为不知道DataContext menas必须将代码放在会降低代码可维护性的地方。
我写了下面的代码(VB,我很害怕),它提供了一个Context属性,可以放在数据对象上,然后用于返回对象所附加的DataContext(如果有的话)。 / p>
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事件以监视对象生命周期内的更改。
如果这样做有帮助,请向我们投票。
有关使用反射查找事件处理程序的更多信息: http://weblogs.asp.net/avnerk/archive/2007/03/29/reflecting-over-an-event.aspx http://www.bobpowell.net/eventsubscribers.htm
答案 1 :(得分:3)
POCO的部分乐趣在于您不能确定对象知道谁正在跟踪他。如果对象具有数据感知/延迟加载属性,那么可能能够通过反射跟踪上下文,但实际上这将是一团糟。简单地将数据上下文传递给需要它的代码会更加清晰。
答案 2 :(得分:2)
最简单的方法是将DataContext传递给您的方法。
但是,您也可以考虑更改设计,以便遵循“单个方法应该只有一个目的”的规则,在这种情况下,您不希望以“修改”的方式“保存” ”