연결 구현(EDM)
EDM(엔터티 데이터 모델)에서 연결은 CSDL(개념 스키마 정의 언어)로 정의됩니다. 연결 구현은 CSDL의 정의를 저장소 메타데이터에 매핑하고, 연결되는 엔터티를 정의하는 스키마와 동일한 스키마에서 연결을 작성합니다.
연결이 저장소에 매핑되고 코드에서 초기화되는 방법과 응용 프로그램에서 연결 데이터를 찾는 방법에 대한 자세한 내용은 이 항목과 연결을 사용한 응용 프로그램 코드(EDM) 항목에서 간단한 형식의 완벽한 예제를 통해 설명합니다.
고객, 주문, 주문 라인 연결
기간 업무(LOB) 응용 프로그램에서 고객과 주문을 나타내는 엔터티는 논리적으로 관련되어 있습니다. 고객이 구매한 제품은 주문으로 표현됩니다. 고객과 주문은 Order_Customer
라는 Association 요소를 사용하여 관련됩니다.
연결의 각 엔터티를 End라고 합니다. 이 연결에서 고객을 나타내는 연결의 End는 여러 주문과 관련될 수 있지만 주문을 나타내는 End는 한 고객과만 관련될 수 있습니다. 이러한 관계는 스키마 구문에서 Multiplicity 특성을 사용하여 정의됩니다. 이 연결에서 Customers
End는 Multiplicity="1"
이고 Orders
End는 Multiplicity="*"
입니다. 이는 일 대 다 연결의 예제입니다. 연결 형식에 대한 자세한 내용은 Association(EDM)을 참조하십시오.
Association 스키마 요소를 사용하여 Order_Customer
연결을 정의하면 이 연결은 이 예제에 사용된 엔터티와 함께 EntityContainer에 AssociationSet으로 포함됩니다. 연결 집합 및 엔터티 컨테이너에 대한 자세한 내용은 EntityContainer 요소(CSDL)를 참조하십시오.
다음 스키마 예제에서는 Customers
, Orders
및 OrderLines
를 나타내는 엔터티와 두 개의 연결인 Order_Customer
및 OrderLine_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
연결과 같은 일 대 다 연결의 Customers
및 Orders
매핑이 데이터베이스의 Orders
및 Customers
테이블 간의 외래 키 관계에 연결을 매핑하는 방식으로 수행됩니다. 이 방법에서는 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로 작성된 이 저장소 스키마는 데이터베이스에서 구현할 경우 Customers
및 Orders
엔터티의 데이터 형식을 지정합니다. CSDL 스키마의 Type="Guid"
에 해당하는 Key 속성은 데이터베이스에 Type="uniqueidentifier"
가 있으며, 저장소 스키마에서 데이터베이스 형식을 사용하여 지정해야 합니다.
CSDL의 String 형식에 해당하는 속성은 저장소의 nvarchar 형식에 매핑됩니다.
저장소 스키마의 연결 사양은 CSDL 스키마의 연결 사양과 같습니다. CSDL 스키마와 마찬가지로 연결 End 요소는 Role, Type 및 Multiplicity 특성을 사용하여 선언됩니다. End 및 Role 할당은 CSDL의 할당과 같습니다.
ReferentialConstraint 특성은 연결이 데이터베이스 구조에 종속됨을 나타냅니다. ReferentialConstraint는 Principle Role 및 Dependent Role과 PropertyRef 요소를 지정합니다. PropertyRef 특성은 Association의 엔터티에 해당하는 데이터베이스 테이블의 기본 키 및 외래 키 열을 나타내는 End 엔터티의 속성을 지정합니다. Principle Role의 PropertyRef 특성은 기본 키를 보유하는 열을 지정합니다. 예를 들어 Order_Customer
연결의 경우 Principle Role의 PropertyRef는 CustomerId
속성입니다. SSDL 스키마에서 이 속성은 Orders
테이블의 외래 키 열인 Customer
에 할당되는 Customers
테이블의 CustomerId
열을 나타냅니다. 외래 키는 Dependent Role의 PropertyRef로 나타냅니다.
매핑 사양
연결 매핑은 엔터티 매핑과 비슷합니다.
다음 MSL(매핑 사양 언어) 세그먼트에서는 Order_Customer
라는 AssociationSetMapping을 보여 줍니다. 이 예제에서는 CSDL 스키마에 지정된 OrderInfoModel.Order_Customer
연결이 데이터베이스를 나타내는 SSDL 스키마의 Orders
테이블에 매핑됩니다.
연결의 Customers
측에 있는 PropertyRef는 명시적으로 Customers
엔터티의 CustomerId
속성을 Orders
테이블의 Customer
열에 매핑하며, 이 열에는 데이터베이스의 Orders
및 Customers
테이블 간의 관계를 나타내는 외래 키가 보유됩니다.
다음 예제에서는 이전 세그먼트에서 추출한 전체 MSL 스키마를 보여 줍니다. 이 매핑에는 이 예제에 필요한 EntitySetMapping 및 AssociationSetMapping 요소가 모두 포함됩니다.
<?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
총계를 구하여 Order
의 TotalAmount
를 계산합니다. 자세한 내용은 도우미 메서드(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 데이터베이스를 만들려면
파일 메뉴에서 새로 만들기를 가리킨 다음 데이터베이스 엔진 쿼리를 클릭합니다.
데이터베이스 엔진에 연결 대화 상자에 localhost 또는 SQL Server 인스턴스의 이름을 입력한 다음 연결을 클릭합니다.
다음 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)