ASP.NET MVC和LINQ一般问题

时间:2009-04-22 09:47:34

标签: asp.net-mvc linq-to-sql

之前我曾就此主题提出过几个问题。在我们能够在工作中实现MVC或LINQ之前,我们需要解决一些问题。

ASP.NET MVC中的多个记录集

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

this tutorial中,我们看到了如何检索数据。但它使用ViewData.Model表示单个结果集,它不解释如果返回多个结果集会发生什么,或者如何获取它们。

强类型存储过程输出

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

在上一节中,我描述了this tutorial,但这也只显示了如何仅为表创建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

它发生在所有userDetail, office, activeUserdept作业上,但我不明白为什么。现在,我还没有正确地映射它们,但是以部门为例。我已经将表模式拖放到dbml文件中,因此它确实存在并且格式正确。

更新

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

无法投放“SingleResult 1[IntranetMVC.Office]' to type 'System.Collections.Generic.IList 1

类型的对象
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

FIX

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

非常感谢!

2 个答案:

答案 0 :(得分:21)

ASP.NET MVC中的多个记录集

是的 - 最肯定的。

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

This blog posts拥有您需要的所有信息。它很简单,非常容易且有效。

您需要做的是两个步骤。

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

    IndexViewData.cs
    public class IndexViewData
    {
        IList<Customers> Customers { get; set; }
        IList<Products> Products { get; set; }
    }
    

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

    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/>
    <% } %>
    
    ...
    

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

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

    强类型存储过程输出

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

    LINQ列查找

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

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

    Bonus Trick!

    如果在将表或存储过程拖放到画布上时运行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;
    }
    

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

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

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

答案 1 :(得分:3)

ASP.NET MVC中的多个记录集:

如果您有存储过程返回A和B.然后您创建一个特定的ViewModel:

public class AB
{
  public A DataA { get; set; };
  public B DataB { get; set; };
}

您也可以使用ViewData字典而不是Model属性(或与此属性结合使用)

强类型存储过程输出

您可以使用自定义字段为存储过程返回的结果创建一个特定的类。

LINQ列查找

不是100%确定这一点,但LINQ在设计时从存储过程中查找列字段名称和参数名称。