سؤال

إذا كان لدي كائنات 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) يعد تمرير كائنين دائمًا بدلاً من كائن واحد نمطًا "قبيحًا" للتطبيق بأكمله.

  • ستحتاج الأساليب إلى المعلمة التالية لكل كائن عمل.
  • سوف تحتاج المجموعة إلى التغيير من "قائمة" إلى "قائمة>".

ستكون صيانة كلتا النقطتين أكثر صعوبة - يجب على المطور في كل مرة تعيين المثيل الصحيح لـ DataContext (من السهل إنشاء خطأ)، على الرغم من أن DataContext يعرف أن الكائن الملموس (أو لا) مرتبط بـ DataContext آخر.

2) أريد (الإصدار الحالي من التطبيق استخدامه) معالجة "أي" منطق عمل على مجموعة من الكائنات التي تأتي من "أماكن" مختلفة (النوافذ العائمة عن طريق السحب والإفلات على سبيل المثال).

نستخدم Currentyl مجموعات بيانات مكتوبة مخصصة، لذلك توجد معلومات حول التغييرات في صفوف البيانات (DataRow = كائن أعمال) ولم تكن هناك مشكلة في الحصول عليها، أو إنشاء نسخة منها ثم حفظها في قاعدة البيانات.

هل كانت مفيدة؟

المحلول

كيفن: أشعر بألمك..عندما تقوم ببناء منطق أعمال حول كائنات عملك، هناك أوقات عندما تقوم ببساطة يملك للوصول إلى DataContext الذي ينتمي إليه الكائن، نظرًا لعدم معرفة قواعد DataContext، يتعين علينا وضع التعليمات البرمجية الخاصة بك في أماكن تقلل من إمكانية صيانة التعليمات البرمجية الخاصة بك.

لقد كتبت الكود التالي (VB، أخشى)، والذي يقدم خاصية سياق يمكن وضعها على كائن بيانات، ثم استخدامها لإرجاع 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

نصائح أخرى

جزء من متعة بوكو هو أنه لا يمكنك التأكد من أن الكائن يعرف الذي يتتبعه.إذا كان الكائن يحتوي على خصائص علم البيانات/تحميل كسول، فأنت قد نكون قادرين على تتبع السياق من خلال التفكير، ولكن في الواقع سيكون هذا فوضى.سيكون من الأنظف بكثير تمرير سياق البيانات إلى الكود الذي يحتاج إليه.

إن أبسط ما يمكنك فعله هو تمرير DataContext إلى طريقتك.

ومع ذلك، قد تفكر أيضًا في تغيير تصميمك بحيث تتبع القاعدة التي تنص على أن "الطريقة الواحدة يجب أن يكون لها غرض واحد فقط"، وفي هذه الحالة لن ترغب في "الحفظ" بنفس الطريقة التي "تعديلها".

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top