我有一个非常大的问题,而且似乎在互联网上找不到其他人有我的问题。我当然希望 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)

在上面的存储过程中,前 3 个参数是用于“创建”类别记录的唯一参数。剩下的参数只是用来告诉我方法内部发生了什么。如果存储过程中的业务规则被破坏,则在业务规则被破坏时,他不会使用 SQL 'RAISEERROR' 关键字。相反,他使用 OUTPUT 参数向我提供有关错误的信息。他对我们数据库中的每个存储过程(甚至更新和删除)都执行此操作。所有“获取”调用都是使用自定义视图完成的。它们都经过了测试,目的是让我的工作变得更轻松,因为我不必添加业务逻辑来捕获所有不同的场景以确保数据质量。

正如我所说,我正在使用 Linq To Sql,现在遇到了一个问题。问题是我的“类别”模型对象只有 4 个属性:CategoryID、CategoryName、UserId 和 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 to Sql 管理此问题的最佳方法是什么?我(个人)认为将所有这些附加属性添加到每个模型对象中没有意义......例如,“Get”永远不应该有错误,并且我不希望我的存储库方法为 Get 调用返回一种类型的对象,而是接受另一种类型的对象用于 CUD 调用。

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

这是我为解决问题所做的事情。我在所有存储库上删除了“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);
 }
scroll top