How to Map Stored Procedures using the ADO.NET Entity Framework

Published 14 September 07 04:34 PM | dpblogs 

 

 

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: http://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

Header#: 43659 Order#: 12 ProductID: 711 Quantity: 4 Price: 20.1865

 

 

Mike Dodaro
Programming Writer, ADO.NET

Filed under:

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# MSDN Blog Postings » How to Map Stored Procedures using the ADO.NET Entity Framework said on September 14, 2007 10:24 PM:

PingBack from http://msdnrss.thecoderblogs.com/2007/09/14/how-to-map-stored-procedures-using-the-adonet-entity-framework/

# Paul Chan said on October 15, 2007 3:51 PM:

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....Paul

# system.data.objects dev guy said on November 8, 2007 5:26 AM:

Entity Framework FAQ Version 0.1 – first draft Contents 1. Introduction . 3 1.1. Why use EDM? How does

# system.data.objects dev guy said on November 8, 2007 5:54 AM:

Version 0.1 – first draft, November 8, 2007 Contents 1. Introduction 1.1. About this FAQ… 1.2. Where

# CAS said on April 9, 2008 5:28 PM:

How do I setup the CSDL for an SP that returns a join of 2 tables?  How to specify the ReturnType in the <FunctionImport>??

# Michael said on May 21, 2008 9:56 AM:

How has it been changed in beta 1? Could it be done in the visual designer?

# 江南白衣 said on June 11, 2008 12:17 PM:

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 degrees

# krishna chandran said on July 15, 2008 7:40 AM:

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.

# Florian S. said on August 5, 2008 10:35 AM:

@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,

Flo

# system.data.objects dev guy said on August 10, 2008 4:27 AM:

Part of the Entity Framework FAQ . 13. EDM 13.1. Does Entity Framework support Abstract types in EDM

# Steve Thomson said on August 18, 2008 1:22 AM:

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.

# John said on October 1, 2008 1:05 AM:

Can anyone tell the solution to the problem stated by Krishna Chandran. Even I am facing the same problem.

Thanks.

John

# richardcollette said on October 15, 2008 1:57 PM:

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?

# Bruno Feliciano said on November 17, 2008 2:30 PM:

Hi..

I'm with the same problem of the Krishna... Yet with no one solution...

Some response from ADO .NET team?

# David said on November 20, 2008 11:50 PM:

After modifying all three sections, you say "Rebuild the model"  How do you "Rebuild the model"?

# Nick Williams said on December 22, 2008 3:05 AM:

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.

# Michael Reyeros said on December 31, 2008 8:25 AM:

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?

# Michael Reyeros said on December 31, 2008 8:46 AM:

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?

# An Phu said on February 9, 2009 2:53 PM:

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.  

# Devart said on August 5, 2009 8:43 AM:

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>

# Kreshiv said on September 10, 2009 7:14 PM:

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.

# AmatAllah said on November 14, 2009 11:34 PM:

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?

Leave a Comment

(required) 
(optional)
(required) 

  
Enter Code Here: Required

Search

This Blog

Syndication

Page view tracker