[转]Entity Framework Sprocs with Multiple Result Sets
本文转自:https://msdn.microsoft.com/en-us/data/jj691402.aspx
Updated: October 23, 2016
Sometimes when using stored procedures you will need to return more than one result set. This scenario is commonly used to reduce the number of database round trips required to compose a single screen. Prior to EF5, Entity Framework would allow the stored procedure to be called but would only return the first result set to the calling code.
This article will show you two ways that you can use to access more than one result set from a stored procedure in Entity Framework. One that uses just code and works with both Code first and the EF Designer and one that only works with the EF Designer. The tooling and API support for this should improve in future versions of Entity Framework.
The examples in this article use a basic Blog and Posts model where a blog has many posts and a post belongs to a single blog. We will use a stored procedure in the database that returns all blogs and posts, something like this:
CREATE PROCEDURE [dbo].[GetAllBlogsAndPosts]
AS
SELECT * FROM dbo.Blogs
SELECT * FROM dbo.Posts
We can execute use code to issue a raw SQL command to execute our stored procedure. The advantage of this approach is that it works with both Code first and the EF Designer.
In order to get multiple result sets working we need to drop to the ObjectContext API by using the IObjectContextAdapter interface.
Once we have an ObjectContext then we can use the Translate method to translate the results of our stored procedure into entities that can be tracked and used in EF as normal. The following code sample demonstrates this in action.
using (var db = new BloggingContext())
{
// If using Code First we need to make sure the model is built before we open the connection
// This isn't required for models created with the EF Designer
db.Database.Initialize(force: false);
// Create a SQL command to execute the sproc
var cmd = db.Database.Connection.CreateCommand();
cmd.CommandText = "[dbo].[GetAllBlogsAndPosts]";
try
{
db.Database.Connection.Open();
// Run the sproc
var reader = cmd.ExecuteReader();
// Read Blogs from the first result set
var blogs = ((IObjectContextAdapter)db)
.ObjectContext
.Translate<Blog>(reader, "Blogs", MergeOption.AppendOnly);
foreach (var item in blogs)
{
Console.WriteLine(item.Name);
}
// Move to second result set and read Posts
reader.NextResult();
var posts = ((IObjectContextAdapter)db)
.ObjectContext
.Translate<Post>(reader, "Posts", MergeOption.AppendOnly);
foreach (var item in posts)
{
Console.WriteLine(item.Title);
}
}
finally
{
db.Database.Connection.Close();
}
}
The Translate method accepts the reader that we received when we executed the procedure, an EntitySet name, and a MergeOption. The EntitySet name will be the same as the DbSet property on your derived context. The MergeOption enum controls how results are handled if the same entity already exists in memory.
Here we iterate through the collection of blogs before we call NextResult, this is important given the above code because the first result set must be consumed before moving to the next result set.
Once the two translate methods are called then the Blog and Post entities are tracked by EF the same way as any other entity and so can be modified or deleted and saved as normal.
Note: EF does not take any mapping into account when it creates entities using the Translate method. It will simply match column names in the result set with property names on your classes.
Note: That if you have lazy loading enabled, accessing the posts property on one of the blog entities then EF will connect to the database to lazily load all posts, even though we have already loaded them all. This is because EF cannot know whether or not you have loaded all posts or if there are more in the database. If you want to avoid this then you will need to disable lazy loading.
Note: You must target .NET Framework 4.5 to be able to configure multiple result sets in EDMX. If you are targeting .NET 4.0 you can use the code-based method shown in the previous section.
If you are using the EF Designer, you can also modify your model so that it knows about the different result sets that will be returned. One thing to know before hand is that the tooling is not multiple result set aware, so you will need to manually edit the edmx file. Editing the edmx file like this will work but it will also break the validation of the model in VS. So if you validate your model you will always get errors.
In order to do this you need to add the stored procedure to your model as you would for a single result set query.
Once you have this then you need to right click on your model and select Open With.. then Xml
.jpeg)
Once you have the model opened as XML then you need to do the following steps:
- Find the complex type and function import in your model:
<!-- CSDL content -->
<edmx:ConceptualModels>
...
<FunctionImport Name="GetAllBlogsAndPosts" ReturnType="Collection(BlogModel.GetAllBlogsAndPosts_Result)" />
...
<ComplexType Name="GetAllBlogsAndPosts_Result">
<Property Type="Int32" Name="BlogId" Nullable="false" />
<Property Type="String" Name="Name" Nullable="false" MaxLength="255" />
<Property Type="String" Name="Description" Nullable="true" />
</ComplexType>
...
</edmx:ConceptualModels>
- Remove the complex type
- Update the function import so that it maps to your entities, in our case it will look like the following:
<FunctionImport Name="GetAllBlogsAndPosts">
<ReturnType EntitySet="Blogs" Type="Collection(BlogModel.Blog)" />
<ReturnType EntitySet="Posts" Type="Collection(BlogModel.Post)" />
</FunctionImport>
This tells the model that the stored procedure will return two collections, one of blog entries and one of post entries.
- Find the function mapping element:
<!-- C-S mapping content -->
<edmx:Mappings>
...
<FunctionImportMapping FunctionImportName="GetAllBlogsAndPosts" FunctionName="BlogModel.Store.GetAllBlogsAndPosts">
<ResultMapping>
<ComplexTypeMapping TypeName="BlogModel.GetAllBlogsAndPosts_Result">
<ScalarProperty Name="BlogId" ColumnName="BlogId" />
<ScalarProperty Name="Name" ColumnName="Name" />
<ScalarProperty Name="Description" ColumnName="Description" />
</ComplexTypeMapping>
</ResultMapping>
</FunctionImportMapping>
...
</edmx:Mappings>
- Replace the result mapping with one for each entity being returned, such as the following:
<ResultMapping>
<EntityTypeMapping TypeName ="BlogModel.Blog">
<ScalarProperty Name="BlogId" ColumnName="BlogId" />
<ScalarProperty Name="Name" ColumnName="Name" />
<ScalarProperty Name="Description" ColumnName="Description" />
</EntityTypeMapping>
</ResultMapping>
<ResultMapping>
<EntityTypeMapping TypeName="BlogModel.Post">
<ScalarProperty Name="BlogId" ColumnName="BlogId" />
<ScalarProperty Name="PostId" ColumnName="PostId"/>
<ScalarProperty Name="Title" ColumnName="Title" />
<ScalarProperty Name="Text" ColumnName="Text" />
</EntityTypeMapping>
</ResultMapping>
It is also possible to map the result sets to complex types, such as the one created by default. To do this you create a new complex type, instead of removing them, and use the complex types everywhere that you had used the entity names in the examples above.
Once these mappings have been changed then you can save the model and execute the following code to use the stored procedure:
using (var db = new BlogEntities())
{
var results = db.GetAllBlogsAndPosts();
foreach (var result in results)
{
Console.WriteLine("Blog: " + result.Name);
}
var posts = results.GetNextResult<Post>();
foreach (var result in posts)
{
Console.WriteLine("Post: " + result.Title);
}
Console.ReadLine();
}
Note: If you manually edit the edmx file for your model it will be overwritten if you ever regenerate the model from the database.
Here we have shown two different methods of accessing multiple result sets using Entity Framework. Both of them are equally valid depending on your situation and preferences and you should choose the one that seems best for your circumstances. It is planned that the support for multiple result sets will be improved in future versions of Entity Framework and that performing the steps in this document will no longer be necessary.
[转]Entity Framework Sprocs with Multiple Result Sets的更多相关文章
- Support for multiple result sets
https://blueprints.launchpad.net/myconnpy/+spec/sp-multi-resultsets Calling a stored procedure can p ...
- Stored Procedures with Multiple Result Sets
Stored Procedures with Multiple Result Sets https://msdn.microsoft.com/en-us/data/jj691402.aspx
- Programming Entity Framework 翻译(1)-目录
1. Introducing the ADO.NET Entity Framework ado.net entity framework 介绍 1 The Entity Relationship Mo ...
- Working with Data » Getting started with ASP.NET Core and Entity Framework Core using Visual Studio » 排序、筛选、分页以及分组
Sorting, filtering, paging, and grouping 7 of 8 people found this helpful By Tom Dykstra The Contoso ...
- Entity Framework Tutorial Basics(41):Multiple Diagrams
Multiple Diagrams in Entity Framework 5.0 Visual Studio 2012 provides a facility to split the design ...
- Code First :使用Entity. Framework编程(6) ----转发 收藏
Chapter6 Controlling Database Location,Creation Process, and Seed Data 第6章 控制数据库位置,创建过程和种子数据 In prev ...
- Code First :使用Entity. Framework编程(7) ----转发 收藏
第7章 高级概念 The Code First modeling functionality that you have seen so far should be enough to get you ...
- Working with Data » Getting started with ASP.NET Core and Entity Framework Core using Visual Studio » 读取关系数据
Reading related data¶ 9 of 9 people found this helpful The Contoso University sample web application ...
- There is already an open DataReader associated with this Command which must be closed first." exception in Entity Framework
Fixing the "There is already an open DataReader associated with this Command which must be clos ...
随机推荐
- [BZOJ4530][Bjoi2014]大融合(LCT)
传送门 大佬们似乎都是用树剖+并查集优雅地A了此题 然后我太弱了,只能打打LCT的板子 虽然的确可以挺无脑的A掉…… 不过至少这题教了我该怎么维护LCT上虚子树的信息,具体看这里 首先,答案很明显是断 ...
- [ActionScript 3.0] 用TextField的方法getCharIndexAtPoint(x:Number, y:Number):int实现文字在固定范围内显示
有时候我们遇到一行文字过多时必须固定文字的显示范围,但由于中英文所占字节数不一样,所以不能很好的用截取字符的方式去统一显示范围的大小,用TextField的getCharIndexAtPoint(x: ...
- [译文]casperjs使用说明-测试
capserjs自带了一个测试框架,它提供了一个使你能够更容易的测试你的web应用的工具集. 注意: 1.1版本变更 这个测试框架,包括它的所有API,仅能使用在casperjs test子命令下 如 ...
- 【UVA10816】Travel in Desert (最小瓶颈路+最短路)
UVA10816 Travel in Desert 题目大意 沙漠中有一些道路,每个道路有一个温度和距离,要求s,t两点间的一条路径,满足温度最大值最小,并且长度最短 输入格式 输入包含多组数据. 每 ...
- docker 创建容器的时候的坑
其实这个题目的话,对于我后面陈述的问题发生的本身并没有太多的联系,但是因为是在docker创建容器的操作之内发生的,所以记录以下 因为网上有些文章有些作者喜欢使用git的命令窗体,说实在的,公司里面用 ...
- Hacking Lambda Expressions in Java
Hacking Lambda Expressions in Javahttps://dzone.com/articles/hacking-lambda-expressions-in-java At t ...
- 进阶篇:5.3.1)均方根法(Root-Sum-Squares,RSS)
本章目的:了解均方根法,运用均方根法. 1.定义 均方根法(Root-Sum-Squares,RSS):均方根法是统计分析法的一种,是把尺寸链中的各个尺寸公差的平方之和再开根即得到关键尺寸的公差. 其 ...
- MySql安装错误代码1045的解决方案
1.MySql安装错误代码1045的解决方案 2.root密码忘记1045的解决方案 错误代码 1045 Access denied for user 'root'@'localhost' (usin ...
- Vue.js 的精髓——组件
开篇:Vue.js 的精髓——组件 写在前面 Vue.js,无疑是当下最火热的前端框架 Almost,而 Vue.js 最精髓的,正是它的组件与组件化.写一个 Vue 工程,也就是在写一个个的组件. ...
- sqlserver 并发机制
一.事务四大属性 分别是原子性.一致性.隔离性.持久性. 1.原子性(Atomicity) 原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库, ...