How to Map Stored Procedures using the ADO.NET Entity Framework
This example provides the basic elements of schema syntax required to map a stored procedure to an Entity Data Model implementation. Implementing stored procedures currently requires manual modifications to the *.edmx file. This example describes the schema syntax and demonstrates how to use stored procedures now.
The sample uses the AdventureWorks database that ships with SQL Server 2005. Only a subset of this large database will be required. You can find an implementation of the model in the documentation topic: https://msdn2.microsoft.com/en-us/library/bb387147(VS.90).aspx . The AdventureWorks Sales Model is an Entity Data Model (EDM) implementation based on the tables in the AdventureWorks sample.
Five entities are declared:
- Address
- Contact
- Product
- SalesOrderDetail
- SalesOrderHeader
This example shows how to implement a stored procedure to return the data contained by the SalesOrderDetail tables related to a single SalesOrderHeader. (The FK_SalesOrderDetail_SalesOrderHeader_SalesOrderID association in this model can do the same thing as this example).
Execute the following query command to implement the stored procedure in the Adventureworks database:
USE AdventureWorks;
GO
IF OBJECT_ID ( 'dbo.GetOrderDetails', 'P' ) IS NOT NULL
DROP PROCEDURE dbo.GetOrderDetails;
GO
CREATE PROCEDURE dbo.GetOrderDetails
@SalesOrderHeaderId int
AS
SELECT SalesOrderID, SalesOrderDetailID, CarrierTrackingNumber,
OrderQty, ProductID, SpecialOfferID, UnitPrice, UnitPriceDiscount,
rowguid, ModifiedDate
FROM Sales.SalesOrderDetail
WHERE SalesOrderID = @SalesOrderHeaderId;
GO
Store Schema Definition Language (SSDL) Requirements
When you select the GetOrderDetails stored procedure along with the five tables in the Entity Data Model wizard, a Function element is generated as part of the AdventureWorks Sales Model. The result in the ssdl schema segment of the *.edmx file will look like this.
<Function Name="GetOrderDetails" Aggregate="false"
BuiltIn="false" NiladicFunction="false"
IsComposable="false"
ParameterTypeSemantics="AllowImplicitConversion"
Schema="dbo">
<Parameter Name="SalesOrderHeaderId" Type="int" Mode="in" />
</Function>
To see this syntax, open the *.edmx file with the Visual Studio XML editor. If the model was generated before you created the stored procedure, simply add the Function syntax to the ssdl segment of the schema inside the Schema tags but not inside the EntityContainer tags.
That's all that's needed in the SSDL segment of the *.edmx file.
Conceptual Schema Definition Language (CSDL) Requirements
Next we need to implement the function import statement in the CSDL segment of the *.edmx file. Add the following XML to the EntityContainer of the csdl segment:
<FunctionImport Name="GetOrderDetails"
EntitySet="SalesOrderDetail"
ReturnType="Collection(AdventureWorksModel.SalesOrderDetail)">
<Parameter Name="SalesOrderHeaderId" Type="Int32" Mode="in">
</Parameter>
</FunctionImport>
That takes care of the CSDL schema requirements.
Mapping Specification Language (MSL) Requirements
Next, the function import from the CSDL model must be mapped to the SSDL model in the MSL portion of the *.edmx file (look for “C-S mapping content”). The function is mapped in the following syntax inside the EntityContainerMapping:
<FunctionImportMapping FunctionImportName="GetOrderDetails"
FunctionName="AdventureWorksModel.Store.GetOrderDetails"/>
Rebuild the model, and the stored procedure with the required parameter should show up in the Object Browser as a method on the AdventureworksEntities namespace: GetOrderDetails(int).
Using the Method in Code
The stored procedure is used in the following code to enumerate results in a foreach loop.
using (AdventureWorksEntities db = new AdventureWorksEntities())
{
int soHeaderNumber = 43659;
foreach (SalesOrderDetail order in db.GetOrderDetails(soHeaderNumber))
Console.WriteLine("Header#: {0} " +
"Order#: {1} ProductID: {2} Quantity: {3} Price: {4}",
soHeaderNumber, order.SalesOrderDetailID, order.ProductID,
order.OrderQty, order.UnitPrice);
}
The output should look like this:
Header#: 43659 Order#: 1 ProductID: 776 Quantity: 1 Price: 2024.9940
Header#: 43659 Order#: 2 ProductID: 777 Quantity: 3 Price: 2024.9940
Header#: 43659 Order#: 3 ProductID: 778 Quantity: 1 Price: 2024.9940
Header#: 43659 Order#: 4 ProductID: 771 Quantity: 1 Price: 2039.9940
Header#: 43659 Order#: 5 ProductID: 772 Quantity: 1 Price: 2039.9940
Header#: 43659 Order#: 6 ProductID: 773 Quantity: 2 Price: 2039.9940
Header#: 43659 Order#: 7 ProductID: 774 Quantity: 1 Price: 2039.9940
Header#: 43659 Order#: 8 ProductID: 714 Quantity: 3 Price: 28.8404
Header#: 43659 Order#: 9 ProductID: 716 Quantity: 1 Price: 28.8404
Header#: 43659 Order#: 10 ProductID: 709 Quantity: 6 Price: 5.7000
Header#: 43659 Order#: 11 ProductID: 712 Quantity: 2 Price: 5.1865
Comments
Anonymous
September 14, 2007
PingBack from http://msdnrss.thecoderblogs.com/2007/09/14/how-to-map-stored-procedures-using-the-adonet-entity-framework/Anonymous
October 15, 2007
How do I setup the CSDL/SSDL/MDL for a SP that returns no resultset? I want to do a SP for inserting a row into a table.. How can I do that.. Thanks....PaulAnonymous
November 07, 2007
Entity Framework FAQ Version 0.1 – first draft Contents 1. Introduction . 3 1.1. Why use EDM? How doesAnonymous
November 07, 2007
Version 0.1 – first draft, November 8, 2007 Contents 1. Introduction 1.1. About this FAQ… 1.2. WhereAnonymous
April 09, 2008
How do I setup the CSDL for an SP that returns a join of 2 tables? How to specify the ReturnType in the <FunctionImport>??Anonymous
May 21, 2008
How has it been changed in beta 1? Could it be done in the visual designer?Anonymous
June 11, 2008
The Entity Framework enables developers to reason about and write queries in terms of the EDM model rather than the logical schema of tables, joins, foreign keys, and so on. Many enterprise systems have multiple applications/databases with varying degreesAnonymous
July 14, 2008
Hai I have been using the NorthWind Database and have been trying to map one of its stored procedures by name “ GetTenMostExpensiveProducts” through the EDM model using <FuctionImport> . I have added the following pieces of code in the csdl and the msl files respectively. <FunctionImport Name="GetTenMostExpensiveProducts" EntitySet="Products" ReturnType="Collection(Self.Products)" /></EntityContainer> <EntityType Name="Customers"> <FunctionImportMapping FunctionImportName="GetTenMostExpensiveProducts" FunctionName="NorthwindModel.Store.Ten_Most_Expensive_Products" /></EntityContainerMapping> There is no parameter in my example as this is returning just the ten most expensive products. Now since the stored procedure is not returning all the row information , when I execure the stored procedure from my application I get this following exception The data reader is incompatible with the specified 'NorthwindModel.Products'. A member of the type, 'ProductID', does not have a corresponding column in the data reader with the same name. It might be because the EDM is trying to map its entities with the column names. The problem is solved when I return all the rows from the stored proc by giving a “ select * “ . I would be grateful if you could give me feedback on the same and help me solve the problem. Regards Krishna chandran Developer MindTree consulting.Anonymous
August 05, 2008
@Paul: Have a look at: http://blogs.microsoft.co.il/blogs/bursteg/archive/2007/12/17/ado-net-entity-framework-tools-stored-procedures.aspx Regards, FloAnonymous
August 09, 2008
Part of the Entity Framework FAQ . 13. EDM 13.1. Does Entity Framework support Abstract types in EDMAnonymous
August 17, 2008
Has anyone found a solution to the problem described by Krishna Chandran? I can repeat this error by using an ObjectDataSource and, in a BLL method, returning a generic list from a sproc. Any help would be much appreciated. Thanks.Anonymous
September 30, 2008
Can anyone tell the solution to the problem stated by Krishna Chandran. Even I am facing the same problem. Thanks. JohnAnonymous
October 15, 2008
I'm there with Krishna Chandran. I create an entity and map it to a function import but there does not appear to be a way to map an entity member to a column number or name returned by the stored procedure. Is this correct?Anonymous
November 17, 2008
Hi.. I'm with the same problem of the Krishna... Yet with no one solution... Some response from ADO .NET team?Anonymous
November 20, 2008
After modifying all three sections, you say "Rebuild the model" How do you "Rebuild the model"?Anonymous
December 21, 2008
I am also looking for a solution to Krishna's problem. It would be nice to get some sort of acknowledgment or explanation from the EF developers on this.Anonymous
December 31, 2008
I have just tried to map a SQL Stored Procedure and am also encountering the same problem as described by Krishna. Has anyone been able to resolve this issue with SPROC mapping with the Entity Framework?Anonymous
December 31, 2008
After doing some testing and modifications to my SPROC, I noticed that it seems that if the SPROC is not returning columns names that are a one to one match to the property names of the Entity Object that you are mapping it to, you will receive this message. For example, in my table I have a column named Product_Id, my model has a property named ProductId, it seems the datareader is returning the column name as Product_Id and this cannot map to the Entity Object that is mapped to the SPROC. My SPROC is simply performing a 'SELECT *...' but I guess this would require one to actually write out all the column names and set up aliases that match the property name and case of the Entity Properties. There must be a better way to do this, team?Anonymous
February 09, 2009
I am having the same problem as described by krishna. This seems like this is a bug. If I change the entity property name to match the column name, everything works.Anonymous
August 05, 2009
We have written a tutorial about working with Oracle stored procedures and Entity Framework here: <a href="http://www.devart.com/blogs/dotconnect/?p=5">http://www.devart.com/blogs/dotconnect/?p=5 </a>Anonymous
September 10, 2009
Is there a solution to The data reader is incompatible with the specified ' '. A member of the type, ' ', does not have a corresponding column in the data reader with the same name.Anonymous
November 14, 2009
I mapped my stored proc as mentioned above but it doesnt appear as object in my data context although it appeared before ,can anyone help?Anonymous
January 25, 2010
It only seems you can use the SP Functions if you return an entity collection. If you select 'none' or 'scalar' then the fuction does not appear added to the context. Not sure if it just gets added elsewhere in these cases