سؤال

أنا أستخدم "تقنية كعب" إلى تحديث بلدي POCO (المستخدمة في سياق منفصل ، ASP.NET MVC).

هذا هو الرمز الذي لدي حاليًا في وحدة التحكم الخاصة بي (الذي يعمل):

[HttpPost]
public ActionResult Edit(Review review)
{
   Review originalReview = _userContentService.FindById(review.PostId) as Review;
   var ctx = _unitOfWork as MySqlServerObjectContext;
   ctx.ApplyCurrentValues("MyEntities.Posts", review);
   _unitOfWork.Commit();
   // ..snip - MVC stuff..
}

كما ترون ، هناك رائحة رمز في كل مكان. قون

بضع نقاط:

  1. أستخدم حقن التبعية (المستند إلى الواجهة) لكل شيء بشكل أساسي
  2. يمكنني استخدام وحدة العمل إلى مجردة ObjectContext وتوفير الثبات عبر مستودعات متعددة
  3. حاليا بلدي Iunitofwork الواجهة لديها طريقة واحدة فقط: void Commit();
  4. وحدة التحكم IUserContentService و IUnitOfWork حقن بواسطة DI
  5. IUserContentService المكالمات Find في المستودعات ، التي تستخدم ObjectContext.

هذان شيئان لا يعجبهما الرمز أعلاه:

  1. لا أريد أن ألقي Iunitofwork كما MySqlServerObjectContext.
  2. لا أريد أن يهتم المراقب ApplyCurrentValues

أريد أساسًا أن يبدو الكود الخاص بي هكذا:

[HttpPost]
public ActionResult Edit(Review review)
{
   _userContentService.Update(review);
   _unitOfWork.Commit();
   // ..snip - MVC stuff..
}

أي أفكار كيف يمكنني فعل ذلك؟ (أو شيئا من هذا القبيل).

لديّ بالفعل ذكاء لتوصيل اسم مجموعة الكيان بناءً على النوع (مزيج من الأدوية الجيرية ، التعددية) ، لذلك لا تقلق كثيرًا بشأن ذلك.

ولكن أتساءل أين أفضل مكان لوضعه ApplyCurrentValues هو؟ لا يبدو من المناسب وضعه في IUnitOfWork واجهة ، لأن هذا هو مصدر قلق الثبات (EF). لنفس السبب أنها لا تنتمي إلى الخدمة. إذا وضعته في بلدي MySqlServerObjectContext الفصل (منطقي) ، من أين أسمي هذا من هذا ، حيث لا يوجد شيء مباشرة يمكن للوصول إلى هذه الفئة - يتم حقنه عبر DI عندما يطلب شيء ما IUnitOfWork.

أي أفكار؟

تعديل

لديّ حل أدناه باستخدام تقنية Stub ، ولكن المشكلة هي إذا كنت قد استرجعت الكيان الذي أقوم بتحديثه مسبقًا ، فهو يلقي استثناءً ، وذكر وجود كيان بهذا المفتاح بالفعل.

ما هو أمر منطقي ، على الرغم من أنني لست متأكدًا من كيفية حل هذا؟

هل أحتاج إلى "التحقق مما إذا كان الكيان مرفقًا بالفعل ، إن لم يكن ، إرفاقه؟"

هل يمكن لأي خبراء EF4 المساعدة هناك؟

تعديل

فما باللك - وجدت الحل ، انظر الإجابة أدناه.

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

المحلول

اكتشفها - لم يكن سهلاً ، لذلك سأحاول شرح أفضل ما أستطيع. (لأولئك الذين يهتمون)

وحدة التحكم ذات الصلة الرمز:

// _userContentService is IUserContentService
_userContentService.Update(review);

لذلك ، تسمى وحدة التحكم الخاصة بي طريقة تسمى Update على IUserContentService, ، يمر عبر القوي Review هدف.

خدمة محتوى المستخدم الرمز ذات الصلة

public void Update(Post post)
{
   // _userContentRepository is IPostRepository
   _userContentRepository.UpdateModel(post);
}

لذلك ، تدعو خدمتي طريقة تسمى UpdateModel على IPostRepository, ، يمر عبر القوي Review هدف.

الآن هنا هو الجزء صعبة.

لدي بالفعل لا مستودعات محددة. انا املك مستودع عام اتصل GenericRepository<T> : IRepository<T>, الذي يتعامل جميع المستودعات المختلفة.

لذلك عندما يطلب شيء ما IPostRepository (وهو ما كانت خدمتي يفعله) ، سوف يعطيها دي GenericRepository<Post>.

لكن الآن ، أعطيها PostRepository:

public class PostRepository : GenericRepository<Post>, IPostRepository
{
   public void UpdateModel(Post post)
   {
      var originalPost = CurrentEntitySet.SingleOrDefault(p => p.PostId == post.PostId);
      Context.ApplyCurrentValues(GetEntityName<Post>(), post);
   }
}

ولأن الفصل مشتق من genericrepository, ، يرث جميع منطق المستودع الأساسي (البحث ، إضافة ، إلخ).

في البداية ، حاولت وضع ذلك updateModel رمز في genericrepository الفصل نفسه (وبعد ذلك لم أكن بحاجة إلى هذا المستودع المحدد) ، لكن المشكلة هي المنطق لاسترداد الكيان الحالي يعتمد على مفتاح كيان معين ، وهو ما GenericRepository<T> لن يعرف عن.

لكن النتيجة النهائية هي التطريز يتم إخفاءه في أعماق طبقة البيانات ، وينتهي بي الأمر بوحدة تحكم نظيفة حقًا.

تعديل

تعمل هذه "تقنية الكعب" هذه أيضًا:

public void UpdateModel(Post post)
{
   var stub = new Review {PostId = post.PostId};
   CurrentEntitySet.Attach(stub);
   Context.ApplyCurrentValues(GetEntityName<Post>(), post);
}

لكن المشكلة هي بسبب بريد مجردة ، لا يمكنني إنشاء مثيل لها ، وبالتالي سأضطر إلى التحقق من نوع المنشور وإنشاء كوب من أجل كل مفرد نوع مشتق. ليس حقا خيار.

تحرير 2 (آخر مرة)

حسنًا ، حصلت على "تقنية الكعب" التي تعمل مع فصول مجردة ، لذلك تم حل مشكلة التزامن الآن.

أضفت معلمة نوع عام إلى بلدي updateModel الطريقة والخاصة القيد الجديد ().

تطبيق:

public void UpdateModel<T>(T post) where T : Post, new()
{
   var stub = new T { PostId = post.PostId };
   CurrentEntitySet.Attach(stub);
   Context.ApplyCurrentValues(GetEntityName<Post>, post);
}

واجهه المستخدم:

void UpdateModel<T>(T post) where T : Post, new();

هذا يمنعني من الاضطرار إلى معرفة نوع T يدويًا ، ويمنع مشاكل التزامن ويمنع أيضًا رحلة إضافية إلى DB.

رائع جدا.

تحرير 3 (اعتقدت أن آخر مرة كانت آخر مرة)

تعمل "تقنية Stub" أعلاه ، ولكن إذا قمت باسترداد الكائن مسبقًا ، فإنه يلقي استثناءًا يوضح كيانًا بهذا المفتاح بالفعل في OSM.

هل يمكن لأي شخص أن ينصح كيفية التعامل مع هذا؟

تحرير 4 (حسنًا - هذا هو!)

لقد وجدت الحل ، بفضل هذا حتى الإجابة: هل من الممكن التحقق مما إذا كان الكائن مرتبطًا بالفعل بسياق بيانات في إطار الكيان؟

كنت قد حاولت "التحقق مما إذا كان الكيان مرفقًا" باستخدام الكود التالي:

ObjectStateEntry entry;
CurrentContext.ObjectStateManager.TryGetObjectStateEntry(entity, out entry);

لكنها عادت دائما لا شيء, ، حتى عندما استكشفت OSM ، يمكنني رؤية كياني هناك بنفس المفتاح.

لكن هذا الرمز يعمل:

CurrentContext.ObjectStateManager.TryGetObjectStateEntry(CurrentContext.CreateEntityKey(CurrentContext.GetEntityName<T>(), entity), out entry)

ربما لأنني أستخدم Pure PoCo ، واجه OSM مشكلة في معرفة مفتاح الكيان ، من يدري.

أوه وشيء آخر أضفته - حتى لا أضطر إلى إضافة مستودع محدد لكل كيان ، قمت بإنشاء سمة تسمى "entitykey"(سمة الممتلكات العامة).

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

لذلك يبحث مستودعك العام عن هذه الخاصية من أجل إنشاء/إعداد كعب.

نعم - يستخدم الانعكاس ، لكنه انعكاس ذكي (يعتمد على السمات) وأنا أستخدم بالفعل انعكاسًا لإضفاء الطابع على أسماء كيان من T.

على أي حال ، تم حل المشكلة - كل شيء على ما يرام الآن!

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