ASP.NET MVC和LINQ一般问题

Kez*_*zer 14 asp.net-mvc linq-to-sql

我以前曾就这个话题问了几个问题.在我们能够在工作中实现MVC或LINQ之前,我们需要解决一些问题.

ASP.NET MVC中的多个记录集

使用的MVC的唯一示例仅返回单个结果集.当使用存储过程时,可以检索多个记录集,并且我们倾向于使用存储过程的全部原因有两个原因(我相信很多人也都知道).首先,如果我们需要传递参数,其次,如果我们想要返回多个数据表.在ASP.NET的MVC架构中,这怎么可能?

本教程中,我们将了解如何检索数据.但是它使用ViewData.Model了表示单个结果集的内容,它没有解释如果返回多个结果集会发生什么,或者如何获取它们.

强类型存储过程输出

此外,ASP.NET网站上使用LINQ进行强类型输出解析的示例是通过使用*.dbml格式实现的,该格式是表模式的镜像,允许使用LINQ查找字段.大.但是,如果您的输出是从不直接映射到视图或表的存储过程自定义的,会发生什么?我们如何从这些存储过程中解析列名?

在上一节中,我描述了本教程,但这也只显示了如何仅为表创建LINQ to SQL,而不是从sproc创建自定义输出.

LINQ列查找

在工作中,我们运行一个宏,它将一堆类导出到我们的App_Code文件夹,因此存储过程参数是预定义的.这样做,所以我们不必调用DeriveParameters,它包含对数据库的额外调用.我们不希望这种情况发生,因为它有很多流量.如果我们使用LINQ,如何解析列数据类型?每当我们定义参数以找出参数的数据类型和名称时,是否有对数据库的调用?事情发生了变化吗?它是否仍然每次都调用DeriveParameters?这些缓存在某个地方吗?

DBML格式

*.dbml文件是否应包含数据库中的所有表?我们有大约15个数据库,每个数据库中有许多表.

每个输出的视图

还有一点要补充这篇文章.而不是手动创建dbml类最好将数据表示为视图,即使它是自定义输出?或者在dbml文件中创建自定义类是否更好?

这必须是最后一个问题,否则我会吃掉自己的手臂

"无法将'SingleResult`1 [IntranetMVC.UserDetail]'类型的对象强制转换为'IntranetMVC.UserDetail'."

这是功能:

  Function Index() As ActionResult
    ViewData("Message") = "Welcome to ASP.NET MVC!"

    Dim userDetail As UserDetail
    Dim office As IList(Of Office)
    Dim activeUser As IList(Of ActiveUser)
    Dim dept As IList(Of Department)

    Using db As PersonnelDataContext = New PersonnelDataContext
      Dim results As IMultipleResults = db.UserDetail(1168)

      userDetail = results.GetResult(Of UserDetail)()
      office = results.GetResult(Of Office)()
      activeUser = results.GetResult(Of ActiveUser)()
      dept = results.GetResult(Of Department)()
    End Using

    Return View(New IndexViewData(userDetail, office, activeUser, dept))
  End Function
Run Code Online (Sandbox Code Playgroud)

它发生在所有userDetail, office, activeUserdept任务上,但我不知道为什么.现在,我还没有正确地映射它们,但是以部门为例.我已经将表模式拖放到dbml文件中,因此它肯定存在并且格式正确.

UPDATE

这是我的实际代码.这不是最终的,我一直在玩它.似乎返回类型不对,但我不确定为什么.它似乎认为当存储过程实际返回四组数据时,只返回一个结果.其中一个集合只有一个结果,其他集合总是返回多个行:

无法转换'SingleResult 1[IntranetMVC.Office]' to type 'System.Collections.Generic.IList1 '类型的对象

Imports System.Data.Linq
Imports System.Reflection
Imports System.Data.Linq.Mapping

Partial Class PersonnelDataContext

  <FunctionAttribute(Name:="dbo.UserDetailProc"), _
  ResultType(GetType(UserDetail)), _
  ResultType(GetType(IList(Of Office))), _
  ResultType(GetType(IList(Of ActiveUser))), _
  ResultType(GetType(IList(Of Department)))> _
  Public Function UserDetail( _
                  <Parameter(Name:="User_Key", DbType:="Int")> ByVal User_Key As Integer, _
                  <Parameter(Name:="EditYN", DbType:="Char")> Optional ByVal EditYN As Char = "N") As IMultipleResults

    Dim result As IExecuteResult = Me.ExecuteMethodCall(Me, CType(MethodInfo.GetCurrentMethod(), MethodInfo), User_Key, EditYN)
    Return CType(result.ReturnValue, IMultipleResults)
  End Function
End Class
Run Code Online (Sandbox Code Playgroud)

固定

好吧,我没有意识到,因为老实说,我没有正确检查返回类型.我假设结果.GetResult(Of MyType)(来自IMultipleResults)会返回一个集合.相反,它只返回单个结果并将指针移动到集合中的下一个项目.不幸的是,GetResult是唯一可以返回结果的公开方法,因此您必须遍历集合并将它们添加到通用列表中.

非常感谢!

Pur*_*ome 21

ASP.NET MVC中的多个记录集

是的 - 最肯定的.

首先,您需要手动创建一个调用存储过程的方法,返回IMultipleResults结果.

此博客文章包含您需要的所有信息.它很简单,非常简单和有效.

你需要做的是两个步骤.

  1. 创建一个调用存储过程并返回多个记录的方法(请参阅上面的博客文章).
  2. 创建一个在视图中使用的简单类对象,控制器设置属性.

例如.

IndexViewData.cs
public class IndexViewData
{
    IList<Customers> Customers { get; set; }
    IList<Products> Products { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

.

HomeController.cs
public ActionResult Index()
{
    IList<Customers> customers;
    IList<Products> products;

    // This grabs the multiple records from a single stored procedure. 
    // This code taken from the blog post link, above.
    using (NorthwindDataContext db = new NorthwindDatacontext)
    {
        IMultipleResults results = db.GetMultipleRecordSets(arg1, ....);
        customers = results.GetResult<Customer>();
        products = results.GetProducts<Product>();
    }

    // Now return the view, with the viewdata that is required.
    return View(new IndexViewData
                    {
                        Customers = customers,
                        Products = products
                    });
}
Run Code Online (Sandbox Code Playgroud)

.

Index.aspx
<%@ Page 
    Language="C#" 
    MasterPageFile="~/Views/Shared/Site.Master" 
    Inherits="System.Web.Mvc.ViewPage<IndexViewData>" %>

<% Html.RenderPartial("CustomersUserControl", 
                       ViewData.Model.Customers); %>

 <br/>

<h2>Products</h2>
<% foreach(var product in ViewData.Model.Products) { %>
Name: <%= product.Name %><br/>
<% } %>

...
Run Code Online (Sandbox Code Playgroud)

请注意,我没有做任何错误检查,等等.这是一个非常快速的pseduo代码指南,让你开始.

注意#2:请注意索引视图是强类型的(它继承了ViewPage.

强类型存储过程输出

我在上面回答了这个问题.请注意,您可以强烈键入您的ISingleResult存储过程.

LINQ列查找

好的,我想我明白你的意思,在这里.当您创建调用存储过程(一个ISingleResult或一个IMultipleResult)的方法时,您正在定义所需的参数,然后......将其视为硬编码.

当您将表拖放到linq到sql context gui canvas时,Visual Studio会在那里执行查找检查.然后,它在上下文的各种文件之一中创建类.例如.NorthwindDataContext.designer等.所以,这是一个一击的工作.创建类后,设计器会在画布上显示该类.有NO SYNC回数据库.没有.纳达.小人物.如果更改数据库模式中的任何内容(例如,添加新字段,更改存储过程参数等),datacontext将不会知道它.您需要删除该表并将其拖放回来.

奖金招数!

如果在将表或存储过程拖放到画布上时运行SQL事件探查器,则可以看到Visual Studio"查询"数据库以获取信息.:)

是的.这是永远不会忘记的.一个一击的工作.需要手动同步.

HTH.

更新

我注意到你又增加了两个q,所以我会在这里添加我的答案.

DBML格式

这是个人决定.15 DB!shees!这是一个公平的数字.无论如何,它归结为Context画布的可维护性.其次,每个上下文都创建它的OWN数据库连接.所以如果你的方法决定调用4个上下文,那么你有4个连接(和往返)到db,dude :)

每个输出的视图

就个人而言,我在Context Canvas上拥有所有表格.我从不在代码中使用这些表类.它们是私有的,仅用于我的Repository namespace/project/dll.我然后使用POCO课程来移动我所有的东西.这使我的代码更清晰,并且不依赖于存储库.

更新#2

这必须是最后一个问题,否则我会吃掉自己的手臂

如果您已将存储的proc拖到linq上下文画布上,请将其删除.不需要引用该方法UserDetails(int userId).

现在,将以下代码(您需要将其转换为VB.NET)添加到数据上下文的部分类(我假设您知道这是什么/意味着什么,顺便说一句): -

[Function("UserDetails")] // <-- This is the name of your stored procedure.
[ResultType(TypeOf(UserDetail))]
[ResultType(TypeOf(Office))]
[ResultType(TypeOf(ActiveUser))]
[ResultType(TypeOf(Department))]
public IMultipleResults UserDetails(
    [Parameter(Name = "UserId", DbType = "Int")] int userId)
//                      /\____     /\_____         ____/\                    
// This is where u _define_ the stored proc arguments.
{
    IExecuteResult result = this.ExecuteMethodCall(this, 
           ((MethodInfo)MethodInfo.GetCurrentMethod())), userId);
// This is where all the stored proc arguments are set ____/\
// This can be multiple args. eg. userId, name, ...
    return (IMultipleResults)result.ReturnValue;
}
Run Code Online (Sandbox Code Playgroud)

然后就像你在以前的VB.NET代码中那样使用它.

问题(我猜)是你没有让方法处理IMultipleResults.您仍在使用旧的存储过程代码签名(默认情况下),它只是一个记录集结果(即.ISingleResult).

如果您将存储从服务器资源管理器拖放到linq Context Canvas上,则这是默认设置.