استخدام الإجراءات المخزنة مع Linq To Sql والتي لها معلمات إضافية

StackOverflow https://stackoverflow.com/questions/1423179

سؤال

أواجه مشكلة كبيرة جدًا ولا يبدو أنني أستطيع العثور على أي شخص آخر على الإنترنت لديه مشكلتي.آمل بالتأكيد أن يساعدني StackOverflow ...

أنا أكتب تطبيق ASP.NET MVC وأستخدم مفهوم المستودع مع Linq To Sql كمخزن بياناتي.كل شيء يعمل بشكل رائع فيما يتعلق باختيار الصفوف من طرق العرض.ومحاصرة قيود قاعدة العمل الأساسية للغاية.ومع ذلك، أواجه مشكلة في تعيينات الإجراءات المخزنة لعمليات الحذف والإدراج والتحديثات.دعني أشرح:

لقد بذل DBA الخاص بنا الكثير من العمل لوضع منطق الأعمال في جميع إجراءاتنا المخزنة حتى لا داعي للقلق بشأن ذلك من ناحيتي.بالتأكيد، أقوم بالتحقق الأساسي، لكنه يدير سلامة البيانات وقيود التاريخ المتضاربة، وما إلى ذلك ...المشكلة التي أواجهها هي أن جميع الإجراءات المخزنة (وأعني الكل) تحتوي على 5 معلمات إضافية (6 للإدخالات) توفر لي المعلومات.الفكرة هي أنه عندما يتعطل شيء ما، يمكنني مطالبة المستخدم بالمعلومات المناسبة من قاعدة البيانات الخاصة بنا.

على سبيل المثال:

sp_AddCategory(
    @userID INT,
    @categoryName NVARCHAR(100),
    @isActive BIT,
    @errNumber INT OUTPUT,
    @errMessage NVARCHAR(1000) OUTPUT,
    @errDetailLogID INT OUTPUT,
    @sqlErrNumber INT OUTPUT,
    @sqlErrMessage NVARCHAR(1000) OUTPUT,
    @newRowID INT OUTPUT)

من الإجراء المخزن أعلاه، فإن المعلمات الثلاث الأولى هي المعلمات الوحيدة المستخدمة "لإنشاء" سجل الفئة.يتم استخدام المعلمات المتبقية ببساطة لإخباري بما حدث داخل الطريقة.إذا تم كسر قاعدة العمل داخل الإجراء المخزن، فإنه لا يستخدم الكلمة الأساسية SQL 'RAISEERROR' عندما يتم كسر قواعد العمل.وبدلاً من ذلك، يقدم لي معلومات حول الخطأ باستخدام معلمات OUTPUT.يقوم بذلك لكل إجراء مخزن في قاعدة البيانات الخاصة بنا حتى التحديثات والحذف.تتم جميع مكالمات "الحصول على" باستخدام طرق عرض مخصصة.لقد تم اختبارها جميعًا وكانت الفكرة هي تسهيل مهمتي حيث لا يتعين علي إضافة منطق العمل لاحتواء جميع السيناريوهات المختلفة لضمان جودة البيانات.

كما قلت، أنا أستخدم Linq To Sql، وأواجه الآن مشكلة.المشكلة هي أن كائن نموذج "الفئة" الخاص بي يحتوي ببساطة على 4 خصائص:معرف الفئة، واسم الفئة، ومعرف المستخدم، وIsActive.عندما فتحت المصمم لبدء تعيين خصائصي للإدراج، أدركت أنه لا توجد طريقة (سهلة) بالنسبة لي لحساب المعلمات الإضافية إلا إذا قمت بإضافتها إلى كائن النموذج الخاص بي.

من الناحية النظرية ما أود القيام به هو هذا:

// note: Repository Methods
public void AddCategory(Category category)
{
    _dbContext.Categories.InsertOnSubmit(category);
}

public void Save()
{
    _dbContext.SubmitChanges();
}

ومن ثم من فئة CategoryController الخاصة بي، أود ببساطة أن أفعل ما يلي:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection collection)
{
    var category = new Category();
    try 
    {
        UpdateModel(category); // simple validation here...

        _repository.AddCategory(category);
        _repository.Save(); // should get error here!!

        return RedirectToAction("Index");
    }
    catch
    {
        // manage friendly messages here somehow... (??)
        // ...

        return View(category);
    }
}

ما هي أفضل طريقة لإدارة ذلك باستخدام Linq إلى Sql؟أنا (شخصيًا) لا أشعر أنه من المنطقي إضافة كل هذه الخصائص الإضافية إلى كل كائن نموذجي...على سبيل المثال، يجب ألا يحتوي "Get" على أية أخطاء مطلقًا ولا أريد أن تقوم أساليب المستودع الخاصة بي بإرجاع نوع واحد من الكائنات لاستدعاءات Get، ولكن تقبل نوعًا آخر من الكائنات لاستدعاءات CUD.

تحديث:بلدي الحل!(ديسمبر.1، 2009)

إليكم ما فعلته لإصلاح مشكلتي.لقد تخلصت من طريقة "Save ()" الخاصة بي في جميع مستودعاتي.بدلاً من ذلك، أضفت طريقة "Update()" إلى كل مستودع وأرسلت البيانات فعليًا إلى قاعدة البيانات في كل CUD (على سبيل المثال.إنشاء / تحديث / حذف) الاتصال.

كنت أعلم أن كل إجراء مخزن له نفس المعلمات، لذلك قمت بإنشاء فئة للاحتفاظ بها:

public class MySprocArgs 
{
    private readonly string _methodName;
    public int? Number;
    public string Message;
    public int? ErrorLogId;
    public int? SqlErrorNumber;
    public string SqlErrorMessage;
    public int? NewRowId;

    public MySprocArgs(string methodName)
    {
        if (string.IsNullOrEmpty(methodName))
            throw new ArgumentNullException("methodName");

        _methodName = methodName;
    }

    public string MethodName
    {
        get { return _methodName; }
    }

}

لقد قمت أيضًا بإنشاء MySprocException الذي يقبل MySprocArgs في مُنشئه:

public class MySprocException : ApplicationException
{

    private readonly MySprocArgs _args;
    public MySprocException(MySprocArgs args) : base(args.Message)
    {
       _args = args;
    }

    public int? ErrorNumber
    {
        get { return _args.Number; }
    }

    public string ErrorMessage
    {
        get { return _args.Message; }
    }

    public int? ErrorLogId
    {
        get { return _args.ErrorLogId; }
    }

    public int? SqlErrorNumber
    {
        get { return _args.SqlErrorNumber; }
    }

    public string SqlErrorMessage
    {
        get { return _args.SqlErrorMessage; }
    }
}

والآن هنا حيث يجتمع كل ذلك...باستخدام المثال الذي بدأت به في استفساري الأولي، إليك الشكل الذي قد تبدو عليه طريقة 'AddCategory()':

public void AddCategory(Category category)
{
   var args = new MySprocArgs("AddCategory");
   var result = _dbContext.AddWidgetSproc(
                    category.CreatedByUserId,
                    category.Name,
                    category.IsActive,
                    ref args.Number, // <-- Notice use of 'args'
                    ref args.Message,
                    ref args.ErrorLogId,
                    ref args.SqlErrorNumber,
                    ref args.SqlErrorMessage,
                    ref args.NewRowId);

   if (result == -1)
      throw new MySprocException(args);
} 

الآن من وحدة التحكم الخاصة بي، أفعل ما يلي ببساطة:

[HandleError(ExceptionType = typeof(MySprocException), View = "SprocError")]
public class MyController : Controller
{
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(Category category)
    {
        if (!ModelState.IsValid)
        { 
            // manage friendly messages        
            return View(category);
        }

        _repository.AddCategory(category);
        return RedirectToAction("Index");

    } 
}

الحيلة لإدارة الجديد MySprocException هو ببساطة اعتراضه باستخدام سمة HandleError وإعادة توجيه المستخدم إلى صفحة تفهم MySprocException.

امل ان يساعد هذا احد ما.:)

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

المحلول

وأنا لا أعتقد أن تتمكن من إضافة معلمات الإخراج إلى أي من الطبقات LINQ بك لأن المعلمات لا تزال قائمة في أي جدول في قاعدة البيانات الخاصة بك.

ولكن يمكنك التعامل مع معلمات الإخراج في LINQ على النحو التالي.

وإضافة الإجراء المخزن (ق) الذي انطلق الدعوة إلى .dbml باستخدام مصمم.

واستدعاء الإجراء المخزن في التعليمات البرمجية

 using (YourDataContext context = new YourDataContext())
 {
    Nullable<int> errNumber = null;
    String errMessage = null;
    Nullable<int> errDetailLogID = null;
    Nullable<int> sqlErrNumber = null;
    String sqlErrMessage = null;
    Nullable<int> newRowID = null;
    Nullable<int> userID = 23;
    Nullable<bool> isActive=true;

    context.YourAddStoredProcedure(userID, "New Category", isActive, ref errNumber, ref errMessage, ref errDetailLogID, ref sqlErrNumber, ref sqlErrMessage, ref newRowID);
 }

نصائح أخرى

لم أجربه بعد، لكن يمكنك إلقاء نظرة على هذه المقالة، حيث يتحدث عن الإجراءات المخزنة التي تُرجع معلمات الإخراج.

http://weblogs.asp.net/scottgu/archive/2007/08/16/linq-to-sql-part-6-retriving-data-using-stored-procedures.aspx

قم بشكل أساسي بسحب الإجراء المخزن إلى LINQ الخاص بك إلى مصمم SQL ثم يجب أن يقوم بالعمل نيابةً عنك.

ووdbContext.SubmitChanges(); سوف تعمل فقط للكيان FRAMEWORK.I تشير إلى حفظ وتحديث وحذف ستعمل باستخدام إجراء مخزن واحد أو باستخدام 3 إجراء مختلف.

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