يلاحظ:
1. يتم إنشاء "الكيانات" المذكورة في هذه المقالة بواسطة LINQ TO SQL (أي dbml)
2. أنت بحاجة إلى فهم كيفية قيام LINQ TO SQL بتنفيذ اقترانات الجدول وEntitySet وEntityRef
ربما بعد رؤية العنوان ستعتقد أن السؤال مجرد نسبياً، لذا دعوني أعطي مثالاً لشرح المشكلة بالتفصيل.
في بنية N-tier المستندة إلى LINQ TO SQL، إذا كنا بحاجة إلى تحديث كيان ما، فيجب أن تكون العملية كما يلي:
عملية
BLL.GetModel(p=>p.id==1) --> تعديل قيمة السمة المقابلة (الحقل) --> BLL.Update(كيان الكيان) --> DAL.Update(كيان الكيان) --> التحديث ناجح
في هذا الوقت، نحتاج إلى تمرير هذا الكيان من طبقة الأعمال (BLL) إلى طبقة الوصول إلى البيانات (DAL). عندما تقوم طريقة GetModel بإرجاع الكيان، سيتم تحرير DataContext على الفور، ثم يتم إعادة مثيله عند DAL. يتم تنفيذ طريقة التحديث (كيان الكيان). قم بإنشاء DataContext لتنفيذ عملية التحديث؛ ويمكن ملاحظة أن الكيان الذي تم تمريره يتم تمريره من DataContext الأول إلى DataContext آخر عند التشغيل عبر DataContexts مختلفة في LINQ TO SQL، تحتاج إلى عمليات إضافية سيتم تنفيذها أولاً، أي context.Entity Attach(entity,true); وأخيرًا context.SubmitChanges();
دعونا نلقي نظرة على الكود:
شفرة
فئة BLL
{
خاص للقراءة فقط DAL dal = new DAL();
LinqToSqlProvider.User GetModel العام (Expression<Func<LinqToSqlProvider.User, bool>> التعبير)
{
dal.GetModel(expression);
}
تحديث الفراغ العام (كيان LinqToSqlProvider.User)
{
dal.Update(entity);
}
}
فئة دال
{
LinqToSqlProvider.User GetModel العام (Expression<Func<LinqToSqlProvider.User, bool>> التعبير)
{
LinqToSqlProvider.User input = new CriTextBroadcast.LinqToSqlProvider.User();
باستخدام (CriTextBroadcastDBDataContext context = DataContext)
{
الإدخال = context.User.SingleOrDefault(expression);
}
دخول العودة؛
}
تحديث الفراغ العام (كيان LinqToSqlProvider.User)
{
باستخدام (CriTextBroadcastDBDataContext context = DataContext)
{
context.User.Attach(entry, true);
context.SubmitChanges();
}
}
}
في الواقع، عندما نستخدم الكود أعلاه للعمل، سيحدث هذا الاستثناء:
تمت محاولة إرفاق كيان أو إضافته، هذا الكيان ليس كيانًا جديدًا، وقد يتم تحميله من DataContext آخر...
بعد التحقق من الكثير من المعلومات دون جدوى، رأيت أخيرا سؤالا مماثلا في منشور أجنبي. وتبين أن الجدول المقابل لهذا الكيان يحتوي على عدة جداول مرتبطة، مثل: المستخدم -> الرسالة، المستخدم -> الصور، إلخ.
سيتم إنشاء سمات مثل EntitySet<Message> تلقائيًا عند إنشاء فئات الكيانات نظرًا لأننا لا نقرأ هذه المحتويات المرتبطة معًا عند الحصول على الكيان، سيحدث ObjectDisposeException في هذه السمات عند إرفاق (Attach). تم استخدامه للاستعلام عن هذا الكيان.
حل:
شفرة
/// <الملخص>
/// يتم فصل كيان LinqToSql المساعد عن DataContext الأصلي
/// </الملخص>
/// <typeparam name="TEntity"></typeparam>
/// <param name="entity"></param>
فصل الفراغ الثابت العام <TEntity> (كيان TEntity)
{
اكتب t = الكيان.GetType();
System.Reflection.PropertyInfo[] property = t.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
foreach (خاصية var في الخصائص)
{
اسم السلسلة = property.Name؛
إذا (property.PropertyType.IsGenericType &&
property.PropertyType.GetGenericTypeDefinition() == typeof(EntitySet<>))
{
property.SetValue(entity, null, null);
}
}
System.Reflection.FieldInfo[] الحقول = t.GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
foreach (حقل var في الحقول)
{
اسم السلسلة = field.Name؛
إذا (field.FieldType.IsGenericType &&
field.FieldType.GetGenericTypeDefinition() == typeof(EntityRef<>))
{
field.SetValue(entity, null);
}
}
System.Reflection.EventInfo eventsPropertyChanged = t.GetEvent("PropertyChanged");
System.Reflection.EventInfo eventsPropertyChanging = t.GetEvent("PropertyChanging");
إذا (eventPropertyChanged != null)
{
eventsPropertyChanged.RemoveEventHandler(entity, null);
}
إذا (eventPropertyChanging != null)
{
eventsPropertyChanging.RemoveEventHandler(entity, null);
}
}
بعد الحصول على الكيان، يجب عليك استخدام طريقة Detach(entity) لفصل الكيان عن DataContext الأصلي، ثم إرفاقه بـ DataContext الجديد.