オブジェクトのDataContextを取得します
-
07-07-2019 - |
質問
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)1ではなく常に2つのオブジェクトを渡すことは「&い」です。アプリケーション全体のパターン。
- メソッドには、すべてのビジネスオブジェクトの次のパラメーターが必要です。
- コレクションを&quot; List&quot;から変更する必要があります&quot; List&gt;&quot;へ。
両方のポイントを維持するのはより困難です-具体的なオブジェクトが別のDataContextにアタッチされている(またはアタッチされていない)ことをDataContextが知っているにもかかわらず、開発者は毎回DataContextの正しいインスタンスを設定する必要があります(バグを作成しやすい)
2)(「現在のバージョンのアプリケーションが使用する」)プロセス&quot; any&quot;さまざまな「場所」に由来するオブジェクトのコレクションに関するビジネスロジック(たとえば、ドラッグ&amp;ドロップによるフローティングウィンドウ)。
Currentylはカスタム型のDataSetを使用しているため、変更に関する情報はデータ行(DataRow =ビジネスオブジェクト)にあり、それを取得すること、またはクローンを作成してデータベースに保存することは問題ありませんでした。
解決
Kevin-私はあなたの痛みを感じます...あなたがあなたのビジネスオブジェクトの周りにビジネスロジックを構築しているとき、あなたが単にオブジェクトが属するDataContextにアクセスする必要がある 時がある、コードの保守性を低下させる場所にコードを配置する必要があることをDataContextメナスが知らない。
次のコード(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
他のヒント
POCO の楽しさの一部は、オブジェクトを確認できないことです。誰が彼を追跡しているかを知っています。オブジェクトがデータベース対応/遅延読み込みのプロパティを持っている場合、リフレクションを介してコンテキストをトレースできる可能性がありますが、実際にはこれは混乱です。データコンテキストを必要とするコードに単純に渡す方がはるかにきれいです。
最も簡単なことは、DataContextをメソッドに渡すことです。
ただし、「単一のメソッドには1つの目的のみ」というルールに従うように設計を変更することも検討できます。この場合、「保存」したくないでしょう。 「変更」と同じ方法で。