연결 구현(EDM)

EDM(엔터티 데이터 모델)에서 연결은 CSDL(개념 스키마 정의 언어)로 정의됩니다. 연결 구현은 CSDL의 정의를 저장소 메타데이터에 매핑하고, 연결되는 엔터티를 정의하는 스키마와 동일한 스키마에서 연결을 작성합니다.

연결이 저장소에 매핑되고 코드에서 초기화되는 방법과 응용 프로그램에서 연결 데이터를 찾는 방법에 대한 자세한 내용은 이 항목과 연결을 사용한 응용 프로그램 코드(EDM) 항목에서 간단한 형식의 완벽한 예제를 통해 설명합니다.

고객, 주문, 주문 라인 연결

기간 업무(LOB) 응용 프로그램에서 고객과 주문을 나타내는 엔터티는 논리적으로 관련되어 있습니다. 고객이 구매한 제품은 주문으로 표현됩니다. 고객과 주문은 Order_Customer라는 Association 요소를 사용하여 관련됩니다.

연결의 각 엔터티를 End라고 합니다. 이 연결에서 고객을 나타내는 연결의 End는 여러 주문과 관련될 수 있지만 주문을 나타내는 End는 한 고객과만 관련될 수 있습니다. 이러한 관계는 스키마 구문에서 Multiplicity 특성을 사용하여 정의됩니다. 이 연결에서 CustomersEndMultiplicity="1"이고 OrdersEndMultiplicity="*"입니다. 이는 일 대 다 연결의 예제입니다. 연결 형식에 대한 자세한 내용은 Association(EDM)을 참조하십시오.

Association 스키마 요소를 사용하여 Order_Customer 연결을 정의하면 이 연결은 이 예제에 사용된 엔터티와 함께 EntityContainerAssociationSet으로 포함됩니다. 연결 집합 및 엔터티 컨테이너에 대한 자세한 내용은 EntityContainer 요소(CSDL)를 참조하십시오.

다음 스키마 예제에서는 Customers, OrdersOrderLines를 나타내는 엔터티와 두 개의 연결인 Order_CustomerOrderLine_Order를 정의합니다.

<?xml version="1.0" encoding="utf-8"?>
      <Schema Namespace="OrderInfoModel" Alias="Self" 
              xmlns="https://schemas.microsoft.com/ado/2006/04/edm">
        <EntityContainer Name="OrderInfoEntities">
          <EntitySet Name="Customers" 
                     EntityType="OrderInfoModel.Customers" />
          <EntitySet Name="OrderLines"
                     EntityType="OrderInfoModel.OrderLines" />
          <EntitySet Name="Orders" 
                     EntityType="OrderInfoModel.Orders" />
          <AssociationSet Name="Order_Customer" 
                          Association="OrderInfoModel.Order_Customer">
            <End Role="Customers" EntitySet="Customers" />
            <End Role="Orders" EntitySet="Orders" />
          </AssociationSet>
          <AssociationSet Name="OrderLine_Order" 
                     Association="OrderInfoModel.OrderLine_Order">
            <End Role="Orders" EntitySet="Orders" />
            <End Role="OrderLines" EntitySet="OrderLines" />
          </AssociationSet>
        </EntityContainer>
        <EntityType Name="Customers">
          <Key>
            <PropertyRef Name="CustomerId" />
          </Key>
          <Property Name="CustomerId" Type="Guid" Nullable="false" />
          <Property Name="Name" Type="String" Nullable="false" 
                    MaxLength="50" Unicode="true" FixedLength="false" />
          <Property Name="Address" Type="String" Nullable="false" 
                    MaxLength="50" Unicode="true" FixedLength="false" />
          <Property Name="City" Type="String" Nullable="false" 
                    MaxLength="50" Unicode="true" FixedLength="false" />
          <Property Name="Phone" Type="String" Nullable="false" 
                    MaxLength="50" Unicode="true" FixedLength="false" />
          <Property Name="ZipCode" Type="Int32" Nullable="false" />
          <NavigationProperty Name="Orders" 
                          Relationship="OrderInfoModel.Order_Customer" 
                          FromRole="Customers" ToRole="Orders" />
        </EntityType>
        <EntityType Name="OrderLines">
          <Key>
            <PropertyRef Name="OrderLineId" />
          </Key>
          <Property Name="OrderLineId" Type="Guid" Nullable="false" />
          <Property Name="ProductName" Type="String" Nullable="false" 
                    MaxLength="50" Unicode="true" FixedLength="false" />
          <Property Name="Quantity" Type="Int32" Nullable="false" />
          <Property Name="UnitPrice" Type="Decimal" Nullable="false" 
                    Precision="19" Scale="4" />
          <Property Name="ExtendedPrice" Type="Decimal" 
                    Nullable="false" Precision="19" Scale="4" />
          <NavigationProperty Name="Orders" 
                          Relationship="OrderInfoModel.OrderLine_Order" 
                          FromRole="OrderLines" ToRole="Orders" />
        </EntityType>
        <EntityType Name="Orders">
          <Key>
            <PropertyRef Name="OrderId" />
          </Key>
          <Property Name="OrderId" Type="String" Nullable="false" 
                    MaxLength="50" Unicode="true" FixedLength="false" />
          <Property Name="TotalAmount" 
                    Type="Decimal" Precision="19" Scale="4" />
          <Property Name="Tax" Type="Decimal" 
                    Precision="19" Scale="4" />
          <Property Name="ShippingAddress" Type="String" 
                    MaxLength="50" Unicode="true" FixedLength="false" />
          <NavigationProperty Name="Customers" 
                    Relationship="OrderInfoModel.Order_Customer" 
                    FromRole="Orders" ToRole="Customers" />
          <NavigationProperty Name="OrderLines" 
                    Relationship="OrderInfoModel.OrderLine_Order" 
                    FromRole="Orders" ToRole="OrderLines" />
        </EntityType>
        <Association Name="Order_Customer">
          <End Role="Customers" 
               Type="OrderInfoModel.Customers" Multiplicity="1" />
          <End Role="Orders" 
               Type="OrderInfoModel.Orders" Multiplicity="*" />
        </Association>
        <Association Name="OrderLine_Order">
          <End Role="Orders" 
               Type="OrderInfoModel.Orders" Multiplicity="1" />
          <End Role="OrderLines" 
               Type="OrderInfoModel.OrderLines" Multiplicity="*" />
        </Association>
      </Schema>

Order_Customer 연결인 NavigationProperty는 편리한 연결 탐색 및 초기화를 제공하기 위해 Customers 엔터티에서 구현되었습니다. 또한 Orders 엔터티는 포함된 OrderLines를 초기화하고 탐색하는 데 사용되는 NavigationProperty를 지정합니다. NavigationProperty 정의에 대한 자세한 내용은 탐색 속성(EDM)을 참조하십시오.

연결 매핑 및 메타데이터

이 예제에서는 Order_Customer 연결과 같은 일 대 다 연결의 CustomersOrders 매핑이 데이터베이스의 OrdersCustomers 테이블 간의 외래 키 관계에 연결을 매핑하는 방식으로 수행됩니다. 이 방법에서는 Customers 외래 키의 여러 인스턴스가 각 고객과 연결된 주문을 나타내는 Orders 테이블에 포함됩니다.

저장소 스키마

다음 SSDL(저장소 스키마 정의 언어) 스키마는 Customers 테이블, Orders 테이블 및 OrderLines 테이블을 나타내는 저장소 메타데이터입니다. SSDL 스키마는 데이터베이스의 테이블에 해당하는 EntityType 요소를 사용하여 이러한 테이블을 선언합니다. 엔터티의 속성은 데이터베이스 관리 시스템의 데이터 형식에 따라 형식화됩니다. 예를 들어 Customers 엔터티의 Name 속성은 CSDL 스키마에 사용되는 String 형식 대신 nvarchar로 형식화됩니다.

<?xml version="1.0" encoding="utf-8"?>
      <Schema Namespace="OrderInfoModel.Store" 
              Alias="Self" Provider="System.Data.SqlClient" 
              ProviderManifestToken="2005" 
xmlns:store="https://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" 
              xmlns="https://schemas.microsoft.com/ado/2006/04/edm/ssdl">
        <EntityContainer Name="OrderInfoModelStoreContainer">
          <EntitySet Name="Customers" 
                     EntityType="OrderInfoModel.Store.Customers" 
                     store:Type="Tables" Schema="dbo" />
          <EntitySet Name="OrderLines" 
                     EntityType="OrderInfoModel.Store.OrderLines" 
                     store:Type="Tables" Schema="dbo" />
          <EntitySet Name="Orders" 
                     EntityType="OrderInfoModel.Store.Orders" 
                     store:Type="Tables" Schema="dbo" />
          <AssociationSet Name="Order_Customer" 
                 Association="OrderInfoModel.Store.Order_Customer">
            <End Role="Customers" EntitySet="Customers" />
            <End Role="Orders" EntitySet="Orders" />
          </AssociationSet>
          <AssociationSet Name="OrderLine_Order" 
                 Association="OrderInfoModel.Store.OrderLine_Order">
            <End Role="Orders" EntitySet="Orders" />
            <End Role="OrderLines" EntitySet="OrderLines" />
          </AssociationSet>
        </EntityContainer>
        <EntityType Name="Customers">
          <Key>
            <PropertyRef Name="CustomerId" />
          </Key>
          <Property Name="CustomerId" 
                    Type="uniqueidentifier" Nullable="false" />
          <Property Name="Name" 
                    Type="nvarchar" Nullable="false" MaxLength="50" />
          <Property Name="Address" 
                    Type="nvarchar" Nullable="false" MaxLength="50" />
          <Property Name="City" 
                    Type="nvarchar" Nullable="false" MaxLength="50" />
          <Property Name="Phone" 
                    Type="nvarchar" Nullable="false" MaxLength="50" />
          <Property Name="ZipCode" 
                    Type="int" Nullable="false" />
        </EntityType>
        <EntityType Name="OrderLines">
          <Key>
            <PropertyRef Name="OrderLineId" />
          </Key>
          <Property Name="OrderLineId" 
                    Type="uniqueidentifier" Nullable="false" />
          <Property Name="OrderId" 
                    Type="nvarchar" Nullable="false" MaxLength="50" />
          <Property Name="ProductName"
                    Type="nvarchar" Nullable="false" MaxLength="50" />
          <Property Name="Quantity" Type="int" Nullable="false" />
          <Property Name="UnitPrice" 
                    Type="money" Nullable="false" />
          <Property Name="ExtendedPrice" 
                    Type="money" Nullable="false" />
        </EntityType>
        <EntityType Name="Orders">
          <Key>
            <PropertyRef Name="OrderId" />
          </Key>
          <Property Name="OrderId" 
                    Type="nvarchar" Nullable="false" MaxLength="50" />
          <Property Name="Customer" 
                    Type="uniqueidentifier" Nullable="false" />
          <Property Name="TotalAmount" Type="money" />
          <Property Name="Tax" 
                    Type="money" />
          <Property Name="ShippingAddress" 
                    Type="nvarchar" MaxLength="50" />
        </EntityType>
        <Association Name="Order_Customer">
          <End Role="Customers"
               Type="OrderInfoModel.Store.Customers" Multiplicity="1" />
          <End Role="Orders" 
               Type="OrderInfoModel.Store.Orders" Multiplicity="*" />
          <ReferentialConstraint>
            <Principal Role="Customers">
              <PropertyRef Name="CustomerId" />
            </Principal>
            <Dependent Role="Orders">
              <PropertyRef Name="Customer" />
            </Dependent>
          </ReferentialConstraint>
        </Association>
        <Association Name="OrderLine_Order">
          <End Role="Orders" 
               Type="OrderInfoModel.Store.Orders" Multiplicity="1" />
          <End Role="OrderLines" 
               Type="OrderInfoModel.Store.OrderLines" Multiplicity="*" />
          <ReferentialConstraint>
            <Principal Role="Orders">
              <PropertyRef Name="OrderId" />
            </Principal>
            <Dependent Role="OrderLines">
              <PropertyRef Name="OrderId" />
            </Dependent>
          </ReferentialConstraint>
        </Association>
      </Schema>

SSDL로 작성된 이 저장소 스키마는 데이터베이스에서 구현할 경우 CustomersOrders 엔터티의 데이터 형식을 지정합니다. CSDL 스키마의 Type="Guid"에 해당하는 Key 속성은 데이터베이스에 Type="uniqueidentifier"가 있으며, 저장소 스키마에서 데이터베이스 형식을 사용하여 지정해야 합니다.

CSDL의 String 형식에 해당하는 속성은 저장소의 nvarchar 형식에 매핑됩니다.

저장소 스키마의 연결 사양은 CSDL 스키마의 연결 사양과 같습니다. CSDL 스키마와 마찬가지로 연결 End 요소는 Role, TypeMultiplicity 특성을 사용하여 선언됩니다. EndRole 할당은 CSDL의 할당과 같습니다.

ReferentialConstraint 특성은 연결이 데이터베이스 구조에 종속됨을 나타냅니다. ReferentialConstraintPrinciple RoleDependent RolePropertyRef 요소를 지정합니다. PropertyRef 특성은 Association의 엔터티에 해당하는 데이터베이스 테이블의 기본 키 및 외래 키 열을 나타내는 End 엔터티의 속성을 지정합니다. Principle RolePropertyRef 특성은 기본 키를 보유하는 열을 지정합니다. 예를 들어 Order_Customer 연결의 경우 Principle RolePropertyRefCustomerId 속성입니다. SSDL 스키마에서 이 속성은 Orders 테이블의 외래 키 열인 Customer에 할당되는 Customers 테이블의 CustomerId 열을 나타냅니다. 외래 키는 Dependent RolePropertyRef로 나타냅니다.

매핑 사양

연결 매핑은 엔터티 매핑과 비슷합니다.

다음 MSL(매핑 사양 언어) 세그먼트에서는 Order_Customer라는 AssociationSetMapping을 보여 줍니다. 이 예제에서는 CSDL 스키마에 지정된 OrderInfoModel.Order_Customer 연결이 데이터베이스를 나타내는 SSDL 스키마의 Orders 테이블에 매핑됩니다.

연결의 Customers측에 있는 PropertyRef는 명시적으로 Customers 엔터티의 CustomerId 속성을 Orders 테이블의 Customer 열에 매핑하며, 이 열에는 데이터베이스의 OrdersCustomers 테이블 간의 관계를 나타내는 외래 키가 보유됩니다.

다음 예제에서는 이전 세그먼트에서 추출한 전체 MSL 스키마를 보여 줍니다. 이 매핑에는 이 예제에 필요한 EntitySetMappingAssociationSetMapping 요소가 모두 포함됩니다.

<?xml version="1.0" encoding="utf-8"?>
      <Mapping Space="C-S" 
   xmlns="urn:schemas-microsoft-com:windows:storage:mapping:CS">
        <EntityContainerMapping 
          StorageEntityContainer="OrderInfoModelStoreContainer" 
          CdmEntityContainer="OrderInfoEntities">
          <EntitySetMapping Name="Customers">
            <EntityTypeMapping 
              TypeName="IsTypeOf(OrderInfoModel.Customers)">
              <MappingFragment StoreEntitySet="Customers">
                <ScalarProperty Name="CustomerId" 
                                ColumnName="CustomerId" />
                <ScalarProperty Name="Name" ColumnName="Name" />
                <ScalarProperty Name="Address" ColumnName="Address" />
                <ScalarProperty Name="City" ColumnName="City" />
                <ScalarProperty Name="Phone" ColumnName="Phone" />
                <ScalarProperty Name="ZipCode" ColumnName="ZipCode" />
              </MappingFragment>
            </EntityTypeMapping>
          </EntitySetMapping>
          <EntitySetMapping Name="OrderLines">
            <EntityTypeMapping 
              TypeName="IsTypeOf(OrderInfoModel.OrderLines)">
              <MappingFragment StoreEntitySet="OrderLines">
                <ScalarProperty Name="OrderLineId" 
                                ColumnName="OrderLineId" />
                <ScalarProperty Name="ProductName" 
                                ColumnName="ProductName" />
                <ScalarProperty Name="Quantity" 
                                ColumnName="Quantity" />
                <ScalarProperty Name="UnitPrice" 
                                ColumnName="UnitPrice" />
                <ScalarProperty Name="ExtendedPrice" 
                                ColumnName="ExtendedPrice" />
              </MappingFragment>
            </EntityTypeMapping>
          </EntitySetMapping>
          <EntitySetMapping Name="Orders">
            <EntityTypeMapping 
              TypeName="IsTypeOf(OrderInfoModel.Orders)">
              <MappingFragment StoreEntitySet="Orders">
                <ScalarProperty Name="OrderId" ColumnName="OrderId" />
                <ScalarProperty Name="TotalAmount" 
                                ColumnName="TotalAmount" />
                <ScalarProperty Name="Tax" ColumnName="Tax" />
                <ScalarProperty Name="ShippingAddress" 
                                ColumnName="ShippingAddress" />
              </MappingFragment>
            </EntityTypeMapping>
          </EntitySetMapping>
          <AssociationSetMapping Name="Order_Customer" 
                               TypeName="OrderInfoModel.Order_Customer" 
                               StoreEntitySet="Orders">
            <EndProperty Name="Customers">
              <ScalarProperty Name="CustomerId" 
                              ColumnName="Customer" />
            </EndProperty>
            <EndProperty Name="Orders">
              <ScalarProperty Name="OrderId" ColumnName="OrderId" />
            </EndProperty>
          </AssociationSetMapping>
          <AssociationSetMapping Name="OrderLine_Order" 
                              TypeName="OrderInfoModel.OrderLine_Order" 
                              StoreEntitySet="OrderLines">
            <EndProperty Name="Orders">
              <ScalarProperty Name="OrderId" 
                              ColumnName="OrderId" />
            </EndProperty>
            <EndProperty Name="OrderLines">
              <ScalarProperty Name="OrderLineId" 
                              ColumnName="OrderLineId" />
            </EndProperty>
          </AssociationSetMapping>
        </EntityContainerMapping>
      </Mapping>

이 항목의 코드 세그먼트에는 OrderInfo 네임스페이스에서 프로그래밍 개체 모델을 빌드하여 저장소에 매핑하는 전체 스키마가 포함되어 있습니다. 이 모델을 사용하는 코드 예제를 보려면 연결을 사용한 응용 프로그램 코드(EDM)를 참조하십시오.

Partial 클래스 메서드

EDM에서는 응용 프로그램의 기능 향상을 위해 도우미 메서드를 partial 클래스에서 구현할 수 있습니다. 다음 예제는 Orders 클래스의 도우미 메서드입니다. 이 도우미 메서드는 주문의 OrderLines에 대한 ExtendedPrice 총계를 구하여 OrderTotalAmount를 계산합니다. 자세한 내용은 도우미 메서드(EDM)를 참조하십시오.

using System;
using System.Data;

namespace OrderInfoModel
{
    public partial class Orders :
                       global::System.Data.Objects.DataClasses.EntityObject
    {
        public decimal ComputeOrder()
        {
            this.TotalAmount = 0;
            foreach (OrderLines orderLine in this.OrderLines)
            {
                orderLine.ExtendedPrice =
                        orderLine.Quantity * orderLine.UnitPrice;
                this.TotalAmount = this.TotalAmount +
                                    orderLine.ExtendedPrice;
            }
           
            this.Tax = Decimal.Round(((decimal)this.TotalAmount *
                                                 (decimal) .08), 2);
            this.TotalAmount = this.TotalAmount + this.Tax;

            return (decimal)this.TotalAmount;

        }
    }
}

데이터베이스 구현

다음 스크립트를 사용하면 이 예제에 필요한 데이터베이스를 만들 수 있습니다. SQL Server Management Studio를 사용하여 OrderInfo 데이터베이스를 만들려면

  1. 파일 메뉴에서 새로 만들기를 가리킨 다음 데이터베이스 엔진 쿼리를 클릭합니다.

  2. 데이터베이스 엔진에 연결 대화 상자에 localhost 또는 SQL Server 인스턴스의 이름을 입력한 다음 연결을 클릭합니다.

  3. 다음 Transact-SQL 스크립트를 쿼리 창에 붙여 넣은 후 실행을 클릭합니다.

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

USE [master]
GO

IF EXISTS (SELECT * FROM sys.databases 
WHERE name = 'OrderInfo')
DROP DATABASE OrderInfo;
GO


-- Create the database.
CREATE DATABASE OrderInfo;
GO

USE OrderInfo;
GO

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[Customers]') AND type in (N'U'))
BEGIN
CREATE TABLE [Customers](
    [CustomerId] [uniqueidentifier] NOT NULL,
    [Name] [nvarchar](50) NOT NULL,
     [Address] [nvarchar](50) NOT NULL,
     [City] [nvarchar](50) NOT NULL,
     [Phone] [nvarchar](50) NOT NULL,
     [ZipCode] [int] NOT NULL,
 CONSTRAINT [PK_Customers] PRIMARY KEY CLUSTERED 
(
[CustomerId] ASC
)WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) 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'[Orders]') AND type in (N'U'))
BEGIN
CREATE TABLE [Orders](
    [OrderId] [nvarchar](50) NOT NULL,
    [Customer] [uniqueidentifier] NOT NULL,
    [TotalAmount] [money] NULL,
    [Tax] [money] NULL,
    [ShippingAddress] [nvarchar](50) NULL,
 CONSTRAINT [PK_Orders] PRIMARY KEY CLUSTERED 
(
     [OrderId] ASC
)WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) 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'[OrderLines]') AND type in (N'U'))
BEGIN
CREATE TABLE [OrderLines](
    [OrderLineId] [uniqueidentifier] NOT NULL,
    [OrderId] [nvarchar](50) NOT NULL,
    [ProductName] [nvarchar](50) NOT NULL,
    [Quantity] [int] NOT NULL,
    [UnitPrice] [money] NOT NULL,
    [ExtendedPrice] [money] NOT NULL,
 CONSTRAINT [PK_OrderLines] PRIMARY KEY CLUSTERED 
(
     [OrderLineId] ASC
)WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[Order_Customer]') AND parent_object_id = OBJECT_ID(N'[Orders]'))
ALTER TABLE [Orders]  WITH CHECK ADD  CONSTRAINT [Order_Customer] FOREIGN KEY([Customer])
REFERENCES [Customers] ([CustomerId])
GO
ALTER TABLE [Orders] CHECK CONSTRAINT [Order_Customer]
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[OrderLine_Order]') AND parent_object_id = OBJECT_ID(N'[OrderLines]'))
ALTER TABLE [OrderLines]  WITH CHECK ADD  CONSTRAINT [OrderLine_Order] FOREIGN KEY([OrderId])
REFERENCES [Orders] ([OrderId])
GO
ALTER TABLE [OrderLines] CHECK CONSTRAINT [OrderLine_Order]

참고 항목

개념

Association(EDM)
탐색 속성(EDM)
엔터티 구현(EDM)

기타 리소스

스키마 및 매핑 사양(Entity Framework)
샘플 응용 프로그램(Entity Framework)