之前我曾就此主题提出过几个问题。在我们能够在工作中实现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, activeUser
和dept
作业上,但我不明白为什么。现在,我还没有正确地映射它们,但是以部门为例。我已经将表模式拖放到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是唯一可以返回结果的公开方法,所以你必须遍历集合并将它们添加到通用列表中。
非常感谢!
答案 0 :(得分:21)
是的 - 最肯定的。
首先,你需要手动创建一个调用存储过程的方法,返回IMultipleResults
结果。
This blog posts拥有您需要的所有信息。它很简单,非常容易且有效。
您需要做的是两个步骤。
例如
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 存储过程。
好的,我想我明白你的意思,在这里。
当您创建调用存储过程(ISingleResult
或IMultipleResult
)的方法时,您正在定义所需的参数,然后......将其视为硬编码
当您将表拖放到linq到sql上下文gui画布时,Visual Studio会在那里执行查找然后。然后,它在上下文的各种文件之一中创建类。例如。 NorthwindDataContext.designer等。所以,它是一击作业。创建类后,设计器会在画布上显示该类。 NO SYNC返回数据库 。没有。纳达。小人物。如果更改数据库模式中的任何内容(例如,添加新字段,更改存储过程参数等),则datacontext将 NOT 了解它。您需要删除该表并将其拖放回来。
如果在将表或存储过程拖放到画布上时运行SQL事件探查器,则可以看到Visual Studio“查询”数据库以获取信息。 :)
所以是的。这是永远不会忘记的。一个一击的工作。需要手动同步。
HTH。
我注意到你又增加了两个q,所以我会在这里添加我的答案。
这是个人决定。 15 DB! shees!这是一个公平的数字。无论如何,它归结为Context画布的可维护性。 其次,每个上下文都创建它的OWN数据库连接。因此,如果你的方法决定调用4个上下文,那么你有4个连接(和往返)到db,dude:)
就个人而言,我在Context Canvas上拥有所有表格。我从不在代码中使用这些表类。它们是私有的,仅用于我的Repository namespace / project / dll。我然后使用POCO类来移动我所有的东西。这使我的代码更清晰,更不依赖于存储库。
如果您已将存储的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在设计时从存储过程中查找列字段名称和参数名称。