3

我有一个非常大的问题,似乎无法在互联网上找到任何其他人有我的问题。我当然希望StackOverflow可以帮助我...使用存储过程与Linq到Sql有其他参数

我正在写一个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) 

从上述的存储过程,所述第一3个参数是用于“创建”的分类记录的唯一参数。其余参数仅用于告诉我在方法内发生了什么。如果业务规则在存储过程中被破坏,那么在业务规则被破坏时,他不会使用SQL'RAISEERROR'关键字。相反,他使用OUTPUT参数向我提供有关错误的信息。他为我们的数据库中的每个存储过程执行此操作,即使是更新和删除。所有'Get'调用都使用自定义视图完成。它们都经过了测试,并且我的想法是让我的工作更轻松,因为我不必添加业务逻辑来捕获所有各种场景以确保数据质量。

正如我所说,我正在使用Linq To Sql,而现在我面临着一个问题。问题是我的“Category”模型对象只有4个属性:CategoryID,CategoryName,UserId和IsActive。当我打开设计器开始映射插入的属性时,我意识到除非将它们添加到我的Model对象中,否则我没有(简单的)方法来解释附加参数。

理论上讲什么,我想这样做是这样的:

// 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 to Sql?我(个人)认为将所有这些附加属性添加到每个模型对象是有意义的...例如,'Get'不应该有错误,我不希望我的存储库方法返回一个获取调用的对象类型,但接受CUD调用的另一种类型的对象。

更新:我的解决方案! (2009年12月1日)

下面是我所做的解决我的问题。我摆脱了我所有存储库中的'Save()'方法。相反,我为每个存储库添加了一个'Update()'方法,并实际将数据提交给每个CUD(即Create/Update/Delete)调用的数据库。

我知道,每个存储过程具有相同的参数,所以我创建了一个类来保存它们:

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; } 
    } 

} 

我还创建了接受MySprocArgs在它的构造函数MySprocException:

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页面陷阱吧。

我希望这有助于某人。 :)

回答

2

我不相信你可以将输出参数添加到任何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); 
} 
+1

非常漂亮。感谢您的反馈。我现在正在修改一个想法,即创建一个全球性的“SprocResult”对象,这个对象将用于所有CUD调用,并按照您的建议手动管理它们。我在我的DataContext上创建了一个方法(使用部分类),它将保存如下所示的调用: context.CallSproc(SprocResult result,params SqlParameter [] args); 再次感谢。有时候,我只需要有人给我种一颗种子。 :)你已经做到了这一点......当我有工作的时候,我一定会用我的解决方案更新我的问题。 – Luc 2009-09-14 19:39:50

+1

已解决!你的建议帮助我解决了我的问题。谢谢!这是我做的:创建一个带有“common”错误变量的SprocArgs类。所以context.AddCategory(...,ref args.ErrorNumber,ref args.ErrorMessage等)。对于我的存储库中的每个CUD方法,我都是逐个手动处理它们。如果一个sproc失败(即。(AddCategory(...)!= 0),那么我只需要抛出新的SprocException(args)。现在唯一要做的就是捕获我的模型对象的属性更改,以便'更新()“'Save()'上的任何脏模型对象谢谢!! – Luc 2009-09-14 21:08:01

+0

@Luc:你可能会把你的解决方案放在你的问题的最后?在评论中,这很难破译,因为你无法格式化代码片段........谢谢! – 2009-09-14 21:34:29

0

我没有'试过它,但你可以看看这篇文章,他谈到返回输出参数的存储过程。

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

基本上拖拽存储过程到您的LINQ to SQL设计那么就应该为你做的工作。

+0

谢谢,我已经读过这个。然而,它并没有解决我的问题......我的问题更多的是关于与模型对象本身不相关的输出参数的问题(例如:errLogID不应该是'Category'模型对象IMO的属性)。感谢您阅读并提供反馈...... – Luc 2009-09-14 19:12:18

+0

如果您只是在您的DAO类中使用dlinq模型,那么您可以创建一个只包含需要传递的数据的模型,并且只处理不要inlucde errLogID。这听起来更像是一个架构问题而不是DLINQ问题。 – 2009-09-14 19:24:54

0

dbContext.SubmitChanges();将只针对实体FRAMEWORK.I建议保存,更新和删除将通过使用单个存储过程或使用3种不同的程序工作。