Mapping Complex Type to Stored Procedures (Entity Framework)

The Entity Data Model (EDM) supports use of stored procedures for data modification to properties of the ComplexType. The example provided in this topic adds stored procedure support to the data model defined in the topic How to: Define a Model with Complex Type.

Storage Model

The stored procedures used in this example are specified in store schema definition language (SSDL). The Function element identifies the stored procedures accessible in the database. Stored procedures are specified for three modification functions used to create, update, and delete instances of the CAddress ComplexType.

<?xml version="1.0" encoding="utf-8"?>
    <Schema Namespace="CustomerComplexAddress.Store"
        Alias="Self" Provider="System.Data.SqlClient"
        ProviderManifestToken="2005"
        xmlns="https://schemas.microsoft.com/ado/2006/04/edm/ssdl">

        <EntityContainer Name="dbo">
          <EntitySet Name="SCustomer"
             EntityType="CustomerComplexAddress.Store.SCustomer" />
        </EntityContainer>

        <EntityType Name="SCustomer">
          <Key>
            <PropertyRef Name="CustomerId" />
          </Key>
          <Property Name="CustomerId" Type="int" Nullable="false" />
          <Property Name="CompanyName" Type="nvarchar" MaxLength="50"/>
          <Property Name="ContactName" Type="nvarchar" MaxLength="50"/>
          <Property Name="ContactTitle" Type="nvarchar" MaxLength="50"/>
          <Property Name="Address" Type="nvarchar" MaxLength="50" />
          <Property Name="City" Type="nvarchar" MaxLength="50" />
          <Property Name="Region" Type="nvarchar" MaxLength="50" />
          <Property Name="PostalCode" Type="nvarchar" MaxLength="50" />
          <Property Name="Country" Type="nvarchar" MaxLength="50" />
          <Property Name="Phone" Type="nvarchar" MaxLength="50" />
          <Property Name="Fax" Type="nvarchar" MaxLength="50" />
        </EntityType>
        <Function Name="CreateCustomerComplexAddress" 
                   Aggregate="false" BuiltIn="false" 
                   NiladicFunction="false" IsComposable="false"
                   ParameterTypeSemantics="AllowImplicitConversion"
                   Schema="dbo">
          <Parameter Name="CustomerId" Type="int" Mode="In" />
          <Parameter Name="CompanyName" Type="nvarchar" Mode="In" />
          <Parameter Name="ContactName" Type="nvarchar" Mode="In" />
          <Parameter Name="ContactTitle" Type="nvarchar" Mode="In" />
          <Parameter Name="Address" Type="nvarchar" Mode="In" />
          <Parameter Name="City" Type="nvarchar" Mode="In" />
          <Parameter Name="Region" Type="nvarchar" Mode="In" />
          <Parameter Name="PostalCode" Type="nvarchar" Mode="In" />
          <Parameter Name="Country" Type="nvarchar" Mode="In" />
          <Parameter Name="Phone" Type="nvarchar" Mode="In" />
          <Parameter Name="Fax" Type="nvarchar" Mode="In" />
        </Function>
        <Function Name="DeleteCustomerComplexAddress" 
                   Aggregate="false" BuiltIn="false"
                   NiladicFunction="false" IsComposable="false"
                   ParameterTypeSemantics="AllowImplicitConversion"
                   Schema="dbo">
          <Parameter Name="CustomerId" Type="int" Mode="In" />
        </Function>
        <Function Name="UpdateCustomerComplexAddress" 
                   Aggregate="false" BuiltIn="false"
                   NiladicFunction="false" IsComposable="false"
                   ParameterTypeSemantics="AllowImplicitConversion"
                   Schema="dbo">
          <Parameter Name="CustomerId" Type="int" Mode="In" />
          <Parameter Name="Address" Type="nvarchar" Mode="In" />
          <Parameter Name="City" Type="nvarchar" Mode="In" />
          <Parameter Name="Region" Type="nvarchar" Mode="In" />
          <Parameter Name="PostalCode" Type="nvarchar" Mode="In" />
          <Parameter Name="Country" Type="nvarchar" Mode="In" />
          <Parameter Name="Phone" Type="nvarchar" Mode="In" />
          <Parameter Name="Fax" Type="nvarchar" Mode="In" />
        </Function>
    </Schema>

The database used in this example can be created by running the following script in SQL Server Management Studio.

USE [master]
GO
IF  EXISTS (SELECT name FROM sys.databases WHERE name = N'CustomerComplexAddress')
DROP DATABASE [CustomerComplexAddress]

CREATE DATABASE [CustomerComplexAddress] 
GO

USE [CustomerComplexAddress]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects 
WHERE object_id = OBJECT_ID(N'[dbo].[SCustomer]') 
AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[SCustomer](
    [CustomerId] [int] NOT NULL,
     [CompanyName] [nvarchar](50) NULL,
     [ContactName] [nvarchar](50) NULL,
     [ContactTitle] [nvarchar](50) NULL,
    [Address] [nvarchar](50) NULL,
     [City] [nvarchar](50) NULL,
     [Region] [nvarchar](50) NULL,
     [PostalCode] [nvarchar](50) NULL,
     [Country] [nvarchar](50) NULL,
     [Phone] [nvarchar](50) NULL,
     [Fax] [nvarchar](50) NULL,
 CONSTRAINT [PK_SCustomer] PRIMARY KEY CLUSTERED 
 (
    [CustomerId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
   IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, 
   ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
END
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

IF NOT EXISTS (SELECT * FROM sys.objects 
WHERE object_id = OBJECT_ID(N'[dbo].[CreateCustomerComplexAddress]') 
AND type in (N'P', N'PC'))
BEGIN
EXEC dbo.sp_executesql @statement = N'
CREATE PROCEDURE [dbo].[CreateCustomerComplexAddress]
   @CustomerId int,
   @CompanyName nvarchar(50),
   @ContactName nvarchar(50),
   @ContactTitle nvarchar(50),
   @Address nvarchar(50),
   @City nvarchar(50),
   @Region nvarchar(50),
   @PostalCode nvarchar(50),
   @Country nvarchar(50),
   @Phone nvarchar(50),
   @Fax nvarchar(50)
   
AS

INSERT INTO [dbo].[SCustomer]
           ([CustomerId]
           ,[CompanyName]
           ,[ContactName]
           ,[Address]
           ,[City]
           ,[Region]
           ,[PostalCode]
           ,[Phone]
           ,[Fax])
     VALUES
           (@CustomerId,
           @CompanyName,
           @ContactName,
           @Address,
           @City,
           @Region,
           @PostalCode,
           @Phone,
           @Fax)
' 
END
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

IF NOT EXISTS (SELECT * FROM sys.objects 
WHERE object_id = OBJECT_ID(N'[dbo].[UpdateCustomerComplexAddress]') 
AND type in (N'P', N'PC'))
BEGIN
EXEC dbo.sp_executesql @statement = N'
CREATE PROCEDURE [dbo].[UpdateCustomerComplexAddress]
   @CustomerId int,
   @Address nvarchar(50),
   @City nvarchar(50),
   @Region nvarchar(50),
   @PostalCode nvarchar(50),
   @Country nvarchar(50),
   @Phone nvarchar(50),
   @Fax nvarchar(50)
AS
UPDATE [dbo].[SCustomer]
   SET [Address] = @Address,
   [City] = @City,
   [Region] = @Region,
   [PostalCode] = @PostalCode,
   [Country] = @Country,
   [Phone] = @Phone,
   [Fax] = @Fax
 WHERE CustomerId = @CustomerId' 
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects 
WHERE object_id = OBJECT_ID(N'[dbo].[DeleteCustomerComplexAddress]') 
AND type in (N'P', N'PC'))
BEGIN
EXEC dbo.sp_executesql @statement = N'
CREATE PROCEDURE [dbo].[DeleteCustomerComplexAddress] 
   @CustomerId int
AS
UPDATE [dbo].[SCustomer]
   SET [Address] = Null,
   [City] = Null,
   [Region] = Null,
   [PostalCode] = Null,
   [Country] = Null,
   [Phone] = Null,
   [Fax] = Null
 WHERE CustomerId = @CustomerId

' 
END

Conceptual Model

The CAddress ComplexType and the CCustomer EntityType that uses it as a property are defined in conceptual schema definition language (CSDL). Use the following schema with edmgen.exe to generate the object model for this example.

<?xml version="1.0" encoding="utf-8"?>
    <Schema Namespace="CustomerComplexAddress"
        Alias="Self"
        xmlns="https://schemas.microsoft.com/ado/2006/04/edm">

        <EntityContainer Name="CustomerComplexAddressContext">
          <EntitySet Name="CCustomers"
               EntityType="CustomerComplexAddress.CCustomer" />
        </EntityContainer>

        <EntityType Name="CCustomer">
          <Key>
            <PropertyRef Name="CustomerId" />
          </Key>
          <Property Name="CustomerId" Type="Int32" Nullable="false" />
          <Property Name="CompanyName" Type="String" />
          <Property Name="ContactName" Type="String" />
          <Property Name="ContactTitle" Type="String" />
          <Property Name="Address" Type="Self.CAddress"
                              Nullable="false" />
        </EntityType>

        <ComplexType Name="CAddress">
          <Property Name="StreetAddress" Type="String" />
          <Property Name="City" Type="String" />
          <Property Name="Region" Type="String" />
          <Property Name="PostalCode" Type="String" />
          <Property Name="Country" Type="String" />
          <Property Name="Phone" Type="String" />
          <Property Name="Fax" Type="String" />
        </ComplexType>
    </Schema>

Mapping Specification

The ModificationFunctionElement that maps stored procedures to the CAddress ComplexType in the conceptual model is defined in mapping specification language (MSL). The following schema shows the mapping for create, update, and delete functions identified in the storage model.

<?xml version="1.0" encoding="utf-8"?>
    <Mapping Space="C-S"
        xmlns="urn:schemas-microsoft-com:windows:storage:mapping:CS">

        <EntityContainerMapping StorageEntityContainer="dbo"
                  CdmEntityContainer="CustomerComplexAddressContext">

          <EntitySetMapping Name="CCustomers">
            <EntityTypeMapping 
              TypeName="CustomerComplexAddress.CCustomer">
              <MappingFragment StoreEntitySet="SCustomer">
                <ScalarProperty Name="CustomerId" 
                                 ColumnName="CustomerId" />
                <ScalarProperty Name="CompanyName" 
                                 ColumnName="CompanyName" />
                <ScalarProperty Name="ContactName" 
                                 ColumnName="ContactName" />
                <ScalarProperty Name="ContactTitle" 
                                 ColumnName="ContactTitle" />
               <ComplexProperty Name="Address"
                       TypeName="CustomerComplexAddress.CAddress">
                 <ScalarProperty Name="StreetAddress" 
                                 ColumnName="Address" />
                 <ScalarProperty Name="City" 
                                 ColumnName="City" />
                 <ScalarProperty Name="Region" 
                                 ColumnName="Region" />
                 <ScalarProperty Name="PostalCode" 
                                 ColumnName="PostalCode" />
                 <ScalarProperty Name="Country" 
                                 ColumnName="Country" />
                 <ScalarProperty Name="Phone" 
                                 ColumnName="Phone" />
                 <ScalarProperty Name="Fax" 
                                 ColumnName="Fax" />
                </ComplexProperty>
              </MappingFragment>
                <ModificationFunctionMapping >
                  <InsertFunction
FunctionName="CustomerComplexAddress.Store.CreateCustomerComplexAddress">
                    <ScalarProperty Name="CustomerId"
                          ParameterName="CustomerId" Version="Current"/>
                    <ScalarProperty Name="CompanyName" 
                                    ParameterName="CompanyName"
                          Version="Current"/>
                    <ScalarProperty Name="ContactName" 
                                    ParameterName="ContactName" 
                                    Version="Current"/>
                     <ScalarProperty Name="ContactTitle"
                          ParameterName="ContactTitle" 
                                     Version="Current"/>
                    <ComplexProperty 
                      TypeName="CustomerComplexAddress.CAddress" 
                      Name="Address">
                    <ScalarProperty Name="StreetAddress" 
                                    ParameterName="Address" 
                                    Version="Current"/>
                    <ScalarProperty Name="City"
                                    ParameterName="City" 
                                    Version="Current"/>
                    <ScalarProperty Name="Region" 
                                    ParameterName="Region" 
                                    Version="Current"/>
                    <ScalarProperty Name="PostalCode"
                          ParameterName="PostalCode" 
                                    Version="Current"/>
                    <ScalarProperty Name="Country"
                                    ParameterName="Country" 
                                    Version="Current"/>
                    <ScalarProperty Name="Phone"
                                    ParameterName="Phone" 
                                    Version="Current"/>
                    <ScalarProperty Name="Fax"
                                    ParameterName="Fax" 
                                    Version="Current"/>
                    </ComplexProperty>
              </InsertFunction>

                <UpdateFunction
FunctionName="CustomerComplexAddress.Store.UpdateCustomerComplexAddress">
                  <ScalarProperty Name="CustomerId"
                                  ParameterName="CustomerId" 
                                  Version="Current"/>
                  <ComplexProperty 
                    TypeName="CustomerComplexAddress.CAddress" 
                    Name="Address">
                  <ScalarProperty Name="StreetAddress"
                        ParameterName="Address" Version="Current"/>
                  <ScalarProperty Name="City"
                        ParameterName="City" Version="Current"/>
                  <ScalarProperty Name="Region" 
                        ParameterName="Region"
                        Version="Current"/>
                  <ScalarProperty Name="PostalCode"
                        ParameterName="PostalCode" Version="Current"/>
                  <ScalarProperty Name="Country"
                        ParameterName="Country" Version="Current"/>
                  <ScalarProperty Name="Phone"
                        ParameterName="Phone" Version="Current"/>
                  <ScalarProperty Name="Fax"
                        ParameterName="Fax" Version="Current"/>
                  </ComplexProperty>
                </UpdateFunction>

                <DeleteFunction
FunctionName="CustomerComplexAddress.Store.DeleteCustomerComplexAddress" >
                  <ScalarProperty Name="CustomerId"
                      ParameterName="CustomerId" Version="Original"/>
                </DeleteFunction>
              </ModificationFunctionMapping>
            </EntityTypeMapping>
          </EntitySetMapping>
       </EntityContainerMapping>
    </Mapping>

To run application code that uses the stored procedures defined and mapped in this example, use the code supplied in the topic How to: Add and Modify Objects with Complex Types (Entity Framework). Stored procedures mapped by using the ModificationFunctionElement are called implicitly when using the data model implemented in this topic. No modifications are required to application code.

See Also

Tasks

How to: Define a Model with Complex Type (Entity Framework)

Concepts

Stored Procedure Support (Entity Framework)