Entity Framework-빠른 가이드

Entity Framework 란 무엇입니까?

Entity Framework는 .NET 응용 프로그램과 관계형 데이터베이스 간의 상호 작용을위한 Microsoft의 기본 수단 인 2008 년에 처음 출시되었습니다. Entity Framework는 소프트웨어의 개체와 관계형 데이터베이스의 테이블 및 열 간의 매핑을 단순화하는 도구 유형 인 ORM (개체 관계형 매퍼)입니다.

  • EF (Entity Framework)는 .NET Framework의 일부인 ADO.NET 용 오픈 소스 ORM 프레임 워크입니다.

  • ORM은 데이터베이스 연결을 생성하고 명령을 실행하는 것은 물론 쿼리 결과를 가져와 해당 결과를 애플리케이션 객체로 자동 구체화합니다.

  • ORM은 또한 이러한 개체에 대한 변경 사항을 추적하는 데 도움이되며 지시를 받으면 해당 변경 사항을 데이터베이스에 다시 유지합니다.

왜 Entity Framework인가?

Entity Framework는 ORM이며 ORM은 응용 프로그램에서 사용되는 데이터를 유지하는 중복 작업을 줄여 개발자의 생산성을 높이는 데 목적이 있습니다.

  • Entity Framework는 데이터베이스에서 데이터를 읽거나 쓰는 데 필요한 데이터베이스 명령을 생성하고 실행할 수 있습니다.

  • 쿼리하는 경우 LINQ to 엔터티를 사용하여 도메인 개체에 대한 쿼리를 표현할 수 있습니다.

  • Entity Framework는 데이터베이스에서 관련 쿼리를 실행 한 다음 앱 내에서 작업 할 수 있도록 결과를 도메인 개체의 인스턴스로 구체화합니다.

NHibernate 및 LLBLGen Pro와 같은 다른 ORM이 시장에 있습니다. 대부분의 ORM은 일반적으로 도메인 유형을 데이터베이스 스키마에 직접 매핑합니다.

Entity Framework에는보다 세분화 된 매핑 계층이 있으므로 예를 들어 단일 엔터티를 여러 데이터베이스 테이블에 매핑하거나 여러 엔터티를 단일 테이블에 매핑하여 매핑을 사용자 지정할 수 있습니다.

  • Entity Framework는 새 응용 프로그램에 대해 Microsoft에서 권장하는 데이터 액세스 기술입니다.

  • ADO.NET은 데이터 세트 및 데이터 테이블에 대한 기술을 직접 참조하는 것 같습니다.

  • Entity Framework는 모든 전진 투자가 이루어지는 곳이며 이미 수년 동안 그랬습니다.

  • 모든 새로운 개발에는 ADO.NET 또는 LINQ to SQL을 통해 Entity Framework를 사용하는 것이 좋습니다.

개념적 모델

데이터베이스 중심 개발에 익숙한 개발자의 경우 Entity Framework의 가장 큰 변화는 비즈니스 도메인에 집중할 수 있다는 것입니다. 데이터베이스가 수행 할 수있는 작업에 제한을받지 않고 애플리케이션이 수행하기를 원하는 것은 무엇입니까?

  • Entity Framework에서는 초점을 개념적 모델이라고합니다. 이는 애플리케이션 데이터를 유지하는 데 사용하는 데이터베이스 모델이 아니라 애플리케이션의 개체 모델입니다.

  • 개념적 모델은 데이터베이스 스키마와 일치하거나 매우 다를 수 있습니다.

  • Visual Designer를 사용하여 개념적 모델을 정의한 다음 궁극적으로 애플리케이션에서 사용할 클래스를 생성 할 수 있습니다.

  • 클래스를 정의하고 Code First라는 Entity Framework의 기능을 사용할 수 있습니다. 그런 다음 Entity Framework는 개념적 모델을 이해합니다.

어느 쪽이든 Entity Framework는 개념적 모델에서 데이터베이스로 이동하는 방법을 알아냅니다. 따라서 개념적 모델 개체에 대해 쿼리하고 직접 작업 할 수 있습니다.

풍모

다음은 Entity Framework의 기본 기능입니다. 이 목록은 가장 주목할만한 기능과 Entity Framework에 대한 질문과 대답을 기반으로 만들어졌습니다.

  • Entity Framework는 Microsoft 도구입니다.
  • Entity Framework는 오픈 소스 제품으로 개발되고 있습니다.
  • Entity Framework는 더 이상 .NET 릴리스주기에 종속되거나 종속되지 않습니다.
  • 유효한 Entity Framework 공급자가있는 모든 관계형 데이터베이스에서 작동합니다.
  • LINQ to Entities에서 SQL 명령 생성.
  • Entity Framework는 매개 변수가있는 쿼리를 만듭니다.
  • 메모리 내 개체의 변경 사항을 추적합니다.
  • 명령 생성을 삽입, 업데이트 및 삭제할 수 있습니다.
  • 시각적 모델 또는 자체 클래스와 함께 작동합니다.
  • Entity Framework에는 저장 프로 시저 지원이 있습니다.

Entity Framework의 아키텍처는 아래에서 위로 다음과 같이 구성됩니다.

데이터 제공자

이들은 개념 스키마에 대해 프로그래밍 할 때 데이터베이스에 연결하기 위해 ADO.NET 인터페이스를 추상화하는 소스 특정 공급자입니다.

명령 트리를 통해 LINQ와 같은 일반적인 SQL 언어를 네이티브 SQL 표현식으로 변환하고 특정 DBMS 시스템에 대해 실행합니다.

엔티티 클라이언트

이 레이어는 엔티티 레이어를 상위 레이어에 노출합니다. 엔터티 클라이언트는 개발자가 개념적 스키마를 나타내는 클래스를 생성 할 필요없이 엔터티 SQL 쿼리를 사용하여 행 및 열 형식의 엔터티에 대해 작업 할 수있는 기능을 제공합니다. Entity Client는 핵심 기능인 엔티티 프레임 워크 계층을 보여줍니다. 이러한 계층을 엔터티 데이터 모델이라고합니다.

  • 그만큼 Storage Layer XML 형식의 전체 데이터베이스 스키마를 포함합니다.

  • 그만큼 Entity Layer 또한 XML 파일은 엔티티와 관계를 정의합니다.

  • 그만큼 Mapping layer 개념 계층에서 정의 된 엔티티 및 관계를 논리적 계층에서 정의 된 실제 관계 및 테이블과 매핑하는 XML 파일입니다.

  • 그만큼 Metadata services Entity Client에서도 표시되는 것은 메타 데이터 저장된 Entity, Mapping 및 Storage 계층에 액세스하기위한 중앙 집중식 API를 제공합니다.

개체 서비스

개체 서비스 계층은 응용 프로그램과 데이터 소스 간의 상호 작용 세션을 나타내는 개체 컨텍스트입니다.

  • 개체 컨텍스트의 주요 용도는 항목의 인스턴스 추가, 삭제와 같은 다양한 작업을 수행하고 쿼리를 사용하여 변경된 상태를 데이터베이스에 다시 저장하는 것입니다.

  • 엔티티의 개체 인스턴스에 대한 데이터 결과를 나타내는 Entity Framework의 ORM 계층입니다.

  • 이 서비스를 통해 개발자는 LINQ 및 Entity SQL을 사용하여 쿼리를 작성하여 기본 키 매핑, 변경 내용 추적 등과 같은 풍부한 ORM 기능 중 일부를 사용할 수 있습니다.

Entity Framework 6의 새로운 기능은 무엇입니까?

프레임 워크에는 모델링에서 런타임 동작에 이르기까지 모든 것을 세부적으로 제어 할 수있는 복잡한 API가 있습니다. Entity Framework 5의 일부는 .NET 내부에 있습니다. 또 다른 부분은 NuGet을 사용하여 배포되는 추가 어셈블리 내부에 있습니다.

  • Entity Framework의 핵심 기능은 .NET Framework에 내장되어 있습니다.

  • Code First 지원은 Entity Framework가 시각적 모델 대신 클래스를 사용할 수 있도록하고 EF와 상호 작용하기위한 더 가벼운 API가 NuGet 패키지에 있습니다.

  • 핵심은 쿼리, 변경 추적 및 쿼리에서 SQL 쿼리로의 모든 변환과 데이터에서 개체로의 반환을 제공하는 것입니다.

  • .NET 4 및 .NET 4.5에서 EF 5 NuGet 패키지를 사용할 수 있습니다.

  • 혼란스러운 점 중 하나-.NET 4.5는 핵심 Entity Framework API에 열거 형 및 공간 데이터에 대한 지원을 추가했습니다. 즉, .NET 4에서 EF 5를 사용하는 경우 이러한 새로운 기능을 사용할 수 없습니다. EF5와 .NET 4.5를 결합 할 때만 얻을 수 있습니다.

이제 Entity Framework 6을 살펴 보겠습니다. Entity Framework 6에서 .NET 내부에 있던 핵심 API는 이제 NuGet 패키지의 일부입니다.

의미-

  • 모든 Entity Framework는 NuGet에서 배포하는이 어셈블리 내부에 있습니다.

  • Entity Framework 열거 형 지원 및 특수 데이터 지원과 같은 특정 기능을 제공하기 위해 .NET에 의존하지 않습니다.

  • EF6의 기능 중 하나는 .NET 4에 대한 열거 형 및 공간 데이터를 지원한다는 것입니다.

Entity Framework에서 작업을 시작하려면 다음 개발 도구를 설치해야합니다.

  • Visual Studio 2013 이상
  • SQL Server 2012 이상
  • NuGet 패키지의 Entity Framework 업데이트

Microsoft는 SQL Server가 포함 된 무료 버전의 Visual Studio를 제공하며 www.visualstudio.com 에서 다운로드 할 수 있습니다 .

설치

Step 1− 다운로드가 완료되면 설치 프로그램을 실행하십시오. 다음 대화 상자가 표시됩니다.

Step 2 − 설치 버튼을 클릭하면 설치 과정이 시작됩니다.

Step 3− 설치 과정이 성공적으로 완료되면 다음 대화 상자가 나타납니다. 이 대화 상자를 닫고 필요한 경우 컴퓨터를 다시 시작하십시오.

Step 4− 시작 메뉴에서 Visual Studio를 열면 다음 대화 상자가 열립니다. 준비는 처음이 될 것입니다.

Step 5 − 모든 작업이 완료되면 Visual Studio의 메인 창이 나타납니다.

File → New → Project에서 새 프로젝트를 만들어 봅시다.

Step 1 − 콘솔 응용 프로그램을 선택하고 확인 버튼을 클릭합니다.

Step 2 − 솔루션 탐색기에서 프로젝트를 마우스 오른쪽 버튼으로 클릭합니다.

Step 3 − 위 이미지와 같이 Manage NuGet Packages를 선택하면 Visual Studio에서 다음 창이 열립니다.

Step 4 − Entity Framework를 검색하고 설치 버튼을 눌러 최신 버전을 설치합니다.

Step 5− 확인을 클릭합니다. 설치가 완료되면 출력 창에 다음 메시지가 표시됩니다.

이제 애플리케이션을 시작할 준비가되었습니다.

이 튜토리얼에서는 간단한 대학 데이터베이스를 사용합니다. 대학 데이터베이스는 전체적으로 훨씬 더 복잡 할 수 있지만 데모 및 학습 목적으로이 데이터베이스의 가장 간단한 형태를 사용합니다. 다음 다이어그램에는 세 개의 테이블이 있습니다.

  • Student
  • Course
  • Enrollment

데이터베이스라는 용어가 사용될 때마다 우리 마음에 직접 떠오르는 것은 일종의 관계를 가진 다른 종류의 테이블입니다. 테이블 간에는 세 가지 유형의 관계가 있으며 서로 다른 테이블 간의 관계는 관련 열이 정의 된 방식에 따라 다릅니다.

  • 일대 다 관계
  • 다 대다 관계
  • 일대일 관계

일대 다 관계

일대 다 관계는 가장 일반적인 관계 유형입니다. 이 유형의 관계에서 테이블 A의 행은 테이블 B에 일치하는 행이 여러 개있을 수 있지만 테이블 B의 행은 테이블 A에 일치하는 행이 하나만있을 수 있습니다. 예를 들어 위 다이어그램에서 Student 및 Enrollment 테이블에는 대 다 관계, 각 학생은 많은 등록을 가질 수 있지만 각 등록은 한 학생에게만 속합니다.

다 대다 관계

다 대다 관계에서 테이블 A의 행은 테이블 B에 일치하는 많은 행을 가질 수 있으며 그 반대의 경우도 마찬가지입니다. 정션 테이블이라는 세 번째 테이블을 정의하여 이러한 관계를 만듭니다.이 테이블의 기본 키는 테이블 A와 테이블 B 모두의 외래 키로 구성됩니다. 예를 들어 Student 및 Course 테이블에는 다음에 정의 된 다 대다 관계가 있습니다. 이러한 각 테이블에서 Enrollment 테이블로의 일대 다 관계.

일대일 관계

일대일 관계에서 테이블 A의 행은 테이블 B에서 일치하는 행을 하나만 가질 수 있으며 그 반대의 경우도 마찬가지입니다. 관련 열이 모두 기본 키이거나 고유 한 제약 조건이있는 경우 일대일 관계가 생성됩니다.

이런 방식으로 관련된 대부분의 정보가 올인원 테이블이기 때문에 이러한 유형의 관계는 일반적이지 않습니다. 당신은 일대일 관계를 사용할 수 있습니다-

  • 열이 많은 테이블을 나눕니다.
  • 보안상의 이유로 테이블의 일부를 분리하십시오.
  • 수명이 짧고 테이블 삭제만으로 쉽게 삭제할 수있는 데이터를 저장합니다.
  • 기본 테이블의 하위 집합에만 적용되는 정보를 저장합니다.

EDM (엔티티 데이터 모델)은 다양한 모델링 기술을 사용하여 데이터의 개념적 모델을 지정하는 Entity-Relationship 모델의 확장 버전입니다. 또한 저장된 형식에 관계없이 데이터 구조를 설명하는 개념 집합을 참조합니다.

EDM은 개념적 모델의 속성을 정의하는 기본 데이터 유형 집합을 지원합니다. 우리는 Entity Framework의 기초를 형성하고 총칭하여 Entity Data Model로 알려진 3 가지 핵심 부분을 고려해야합니다. 다음은 EDM의 세 가지 핵심 부분입니다.

  • 스토리지 스키마 모델
  • 개념적 모델
  • 매핑 모델

스토리지 스키마 모델

SSDL (Storage Schema Definition Layer)이라고도하는 스토리지 모델은 백엔드 데이터 저장소의 도식 표현을 나타냅니다.

개념적 모델

CSDL (Conceptual Schema Definition Layer)이라고도하는 개념적 모델은 쿼리를 작성하는 실제 엔터티 모델입니다.

매핑 모델

매핑 계층은 개념적 모델과 스토리지 모델 간의 매핑 일뿐입니다.

논리적 스키마 및 물리적 스키마와의 매핑은 EDM으로 표시됩니다.

  • Visual Studio는 EDM 및 매핑 사양의 시각적 생성을위한 Entity Designer도 제공합니다.

  • 도구의 출력은 스키마와 매핑을 지정하는 XML 파일 (* .edmx)입니다.

  • Edmx 파일에는 Entity Framework 메타 데이터 아티팩트가 포함되어 있습니다.

스키마 정의 언어

ADO.NET Entity Framework는 SDL (스키마 정의 언어)이라는 XML 기반 데이터 정의 언어를 사용하여 EDM 스키마를 정의합니다.

  • SDL은 String, Int32, Double, Decimal, DateTime 등 다른 기본 유형과 유사한 단순 유형을 정의합니다.

  • 기본 값과 이름의 맵을 정의하는 열거 형도 단순 유형으로 간주됩니다.

  • 열거 형은 프레임 워크 버전 5.0 이상에서만 지원됩니다.

  • 복합 유형은 다른 유형의 집계에서 생성됩니다. 이러한 유형의 속성 컬렉션은 엔티티 유형을 정의합니다.

데이터 모델은 주로 데이터 구조를 설명하는 세 가지 핵심 개념을 가지고 있습니다.

  • 엔티티 유형
  • 협회 유형
  • Property

엔티티 유형

엔티티 유형은 EDM에서 데이터 구조를 설명하기위한 기본 구성 요소입니다.

  • 개념적 모델에서 엔터티 유형은 속성에서 구성되며 비즈니스 응용 프로그램의 학생 및 등록과 같은 최상위 개념의 구조를 설명합니다.

  • 엔터티는 특정 학생 또는 등록과 같은 특정 개체를 나타냅니다.

  • 각 항목에는 항목 집합 내에 고유 한 항목 키가 있어야합니다. 항목 집합은 특정 항목 유형의 인스턴스 모음입니다. 엔티티 세트 (및 연관 세트)는 엔티티 컨테이너에서 논리적으로 그룹화됩니다.

  • 상속은 엔티티 유형에서 지원됩니다. 즉, 한 엔티티 유형이 다른 엔티티에서 파생 될 수 있습니다.

협회 유형

EDM의 관계를 설명하기위한 또 다른 기본 구성 요소입니다. 개념적 모델에서 연결은 Student 및 Enrollment와 같은 두 엔터티 유형 간의 관계를 나타냅니다.

  • 모든 연결에는 연결에 관련된 엔터티 유형을 지정하는 두 개의 연결 끝이 있습니다.

  • 각 연결 끝은 연결 끝 부분에있을 수있는 엔터티 수를 나타내는 연결 끝 다중도도 지정합니다.

  • 연관 끝 다중성은 1, 0 또는 1 (0..1) 또는 다수 (*)의 값을 가질 수 있습니다.

  • 연결의 한쪽 끝에있는 엔터티는 탐색 속성을 통해 액세스하거나 엔터티 유형에 노출 된 경우 외래 키를 통해 액세스 할 수 있습니다.

특성

항목 유형에는 구조와 특성을 정의하는 속성이 포함됩니다. 예를 들어 Student 엔터티 유형에는 Student Id, Name 등과 같은 속성이있을 수 있습니다.

속성에는 기본 데이터 (예 : 문자열, 정수 또는 부울 값) 또는 구조화 된 데이터 (예 : 복합 유형)가 포함될 수 있습니다.

Entity Framework를 사용하면 엔터티로 알려진 CLR (공용 언어 런타임) 개체를 사용하여 데이터를 쿼리, 삽입, 업데이트 및 삭제할 수 있습니다. Entity Framework는 모델에 정의 된 엔터티와 관계를 데이터베이스에 매핑합니다. 그것은 또한 시설을 제공합니다-

  • 데이터베이스에서 반환 된 데이터를 엔티티 객체로 구체화
  • 개체에 대한 변경 사항 추적
  • 동시성 처리
  • 개체 변경 사항을 데이터베이스로 다시 전파
  • 컨트롤에 개체 바인딩

개체로서 데이터와 상호 작용하는 기본 클래스는 System.Data.Entity.DbContext입니다. DbContext API는 .NET Framework의 일부로 릴리스되지 않았습니다. Code First 및 DbContext API에 새로운 기능을 릴리스하여보다 유연하고 빈번하게하기 위해 Entity Framework 팀은 Microsoft의 NuGet 배포 기능을 통해 EntityFramework.dll을 배포합니다.

  • NuGet을 사용하면 웹에서 관련 DLL을 프로젝트로 직접 가져 와서 .NET 프로젝트에 대한 참조를 추가 할 수 있습니다.

  • 라이브러리 패키지 관리자라고하는 Visual Studio 확장은 웹에서 프로젝트로 적절한 어셈블리를 쉽게 가져올 수있는 방법을 제공합니다.

  • DbContext API는 주로 Entity Framework와의 상호 작용을 단순화하는 데 사용됩니다.

  • 또한 일반적으로 사용되는 작업에 액세스하는 데 필요한 메서드 및 속성의 수도 줄어 듭니다.

  • 이전 버전의 Entity Framework에서는 이러한 작업을 검색하고 코딩하기가 복잡했습니다.

  • 컨텍스트 클래스는 런타임 동안 개체 개체를 관리합니다. 여기에는 데이터베이스의 데이터로 개체 채우기, 변경 내용 추적 및 데이터베이스에 대한 데이터 유지가 포함됩니다.

DbContext 파생 클래스 정의

컨텍스트 작업에 권장되는 방법은 DbContext에서 파생되는 클래스를 정의하고 컨텍스트에서 지정된 엔터티의 컬렉션을 나타내는 DbSet 속성을 노출하는 것입니다. EF 디자이너로 작업하는 경우 컨텍스트가 생성됩니다. Code First로 작업하는 경우 일반적으로 컨텍스트를 직접 작성합니다.

다음 코드는 UniContext가 DbContext에서 파생되었음을 보여주는 간단한 예제입니다.

  • getter 및 setter와 같은 DbSet과 함께 자동 속성을 사용할 수 있습니다.

  • 또한 훨씬 더 깔끔한 코드를 만들지 만 적용 할 다른 논리가 없을 때 DbSet을 만들 목적으로 사용할 필요는 없습니다.

public class UniContext : DbContext {
   public UniContext() : base("UniContext") { }
   public DbSet<Student> Students { get; set; }
   public DbSet<Enrollment> Enrollments { get; set; }
   public DbSet<Course> Courses { get; set; }
}
  • 이전에는 EDM이 ObjectContext 클래스에서 파생 된 컨텍스트 클래스를 생성하는 데 사용되었습니다.

  • ObjectContext로 작업하는 것은 약간 복잡했습니다.

  • DbContext는 ObjectContext를 둘러싼 래퍼로 실제로 ObjectContext와 유사하며 Code First, Model First 및 Database First와 같은 모든 개발 모델에서 유용하고 쉽습니다.

쿼리

다음과 같은 세 가지 유형의 쿼리를 사용할 수 있습니다.

  • 새 엔티티 추가.
  • 기존 엔터티의 속성 값 변경 또는 업데이트.
  • 기존 엔티티 삭제.

새 엔티티 추가

Entity Framework를 사용하여 새 개체를 추가하는 것은 개체의 새 인스턴스를 생성하고 DbSet에서 Add 메서드를 사용하여 등록하는 것처럼 간단합니다. 다음 코드는 새 학생을 데이터베이스에 추가하려는 경우입니다.

private static void AddStudent() {

   using (var context = new UniContext()) {

      var student = new Student {
         LastName = "Khan", 
         FirstMidName = "Ali", 
         EnrollmentDate = DateTime.Parse("2005-09-01") 
      };

      context.Students.Add(student); 
      context.SaveChanges();

   }
}

기존 엔티티 변경

기존 객체를 변경하는 것은 변경하려는 속성에 할당 된 값을 업데이트하고 SaveChanges를 호출하는 것만 큼 간단합니다. 다음 코드에서 Ali의 성이 Khan에서 Aslam으로 변경되었습니다.

private static void AddStudent() {

   private static void ChangeStudent() {

      using (var context = new UniContext()) {

         var student = (from d in context.Students
            where d.FirstMidName == "Ali" select d).Single();
         student.LastName = "Aslam";
         context.SaveChanges();

      }
   }
}

기존 엔티티 삭제

Entity Framework를 사용하여 엔터티를 삭제하려면 DbSet에서 Remove 메서드를 사용합니다. 제거는 기존 및 새로 추가 된 엔티티 모두에 대해 작동합니다. 추가되었지만 아직 데이터베이스에 저장되지 않은 엔티티에 대해 Remove를 호출하면 엔티티 추가가 취소됩니다. 엔티티가 변경 추적기에서 제거되고 더 이상 DbContext에 의해 추적되지 않습니다. 변경 추적중인 기존 엔티티에 대해 Remove를 호출하면 다음에 SaveChanges가 호출 될 때 삭제할 엔티티가 등록됩니다. 다음 예는 이름이 Ali 인 데이터베이스에서 학생이 제거 된 인스턴스를 보여줍니다.

private static void DeleteStudent() {

   using (var context = new UniContext()) {
      var bay = (from d in context.Students where d.FirstMidName == "Ali" select d).Single();
      context.Students.Remove(bay);
      context.SaveChanges();
   }
}

Entity Framework에는 개발자가 데이터 클래스 자체를 수정하지 않고도 데이터 모델과 함께 자신의 사용자 지정 데이터 클래스를 사용할 수 있도록하는 두 가지 유형의 엔터티가 있습니다.

  • POCO 엔티티
  • 동적 프록시

POCO 법인

  • POCO는 데이터 모델과 함께 기존 도메인 개체로 사용할 수있는 "일반적인"CLR 개체를 나타냅니다.

  • 엔티티에 매핑되는 POCO 데이터 클래스는 데이터 모델에 정의됩니다.

  • 또한 엔터티 데이터 모델 도구에서 생성 된 엔터티 유형과 동일한 쿼리, 삽입, 업데이트 및 삭제 동작을 대부분 지원합니다.

  • POCO 템플릿을 사용하여 개념적 모델에서 지속성 무시 엔터티 유형을 생성 할 수 있습니다.

개념적 엔터티 데이터 모델의 다음 예를 살펴 보겠습니다.

위의 엔티티 모델에 대한 POCO 엔티티를 생성하려면-

Step 1− 디자이너 창을 마우스 오른쪽 버튼으로 클릭합니다. 다음 대화 상자가 표시됩니다.

Step 2 − 코드 생성 항목 추가 ...를 선택합니다.

Step 3 − EF 6.x DbContext Generator를 선택하고 이름을 작성한 후 추가 버튼을 클릭합니다.

솔루션 탐색기에서 POCODemo.Context.tt 및 POCODemo.tt 템플릿이 생성 된 것을 볼 수 있습니다.

POCODemo.Context는 컨텍스트, 학생 및 코스 등에 대해 반환하고 쿼리에 사용할 수있는 DbContext 및 개체 집합을 생성합니다.

다른 템플릿은 Student, Courses 등의 모든 유형을 다룹니다. 다음은 Entity Model에서 자동으로 생성되는 Student 클래스의 코드입니다.

namespace ConsoleApplication1 {

   using System;
   using System.Collections.Generic;

   public partial class Student {

      [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", 
         "CA2214:DoNotCallOverridableMethodsInConstructors")]

      public Student() {
         this.Enrollments = new HashSet<Enrollment>();
      }

      public int ID { get; set; }
      public string LastName { get; set; }
      public string FirstMidName { get; set; }
      public System.DateTime EnrollmentDate { get; set; }

      [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", 
         CA2227:CollectionPropertiesShouldBeReadOnly")]

      public virtual ICollection<Enrollment> Enrollments { get; set; }

   }
}

엔터티 모델의 과정 및 등록 테이블에 대해 유사한 클래스가 생성됩니다.

동적 프록시

POCO 엔터티 유형의 인스턴스를 만들 때 Entity Framework는 종종 엔터티의 프록시 역할을하는 동적으로 생성 된 파생 형식의 인스턴스를 만듭니다. IT는 또한 POCO 엔티티의 래퍼 클래스와 같은 런타임 프록시 클래스라고 말할 수 있습니다.

  • 속성에 액세스 할 때 작업을 자동으로 수행하도록 엔터티의 일부 속성을 재정의 할 수 있습니다.

  • 이 메커니즘은 관계의 지연로드 및 자동 변경 추적을 지원하는 데 사용됩니다.

  • 이 기술은 Code First 및 EF Designer로 생성 된 모델에도 적용됩니다.

Entity Framework가 관련 개체의 지연로드를 지원하고 POCO 클래스의 변경 사항을 추적하려면 POCO 클래스가 다음 요구 사항을 충족해야합니다.

  • 사용자 지정 데이터 클래스는 공개 액세스로 선언해야합니다.

  • 사용자 지정 데이터 클래스는 봉인되지 않아야합니다.

  • 사용자 정의 데이터 클래스는 추상이 아니어야합니다.

  • 사용자 지정 데이터 클래스에는 매개 변수가없는 공용 또는 보호 된 생성자가 있어야합니다.

  • POCO 엔터티에 대한 프록시를 만드는 데 CreateObject 메서드를 사용하려면 매개 변수없이 보호 된 생성자를 사용합니다.

  • CreateObject 메서드를 호출한다고해서 프록시 생성이 보장되는 것은 아닙니다. POCO 클래스는이 항목에 설명 된 다른 요구 사항을 따라야합니다.

  • 프록시 클래스는 이러한 인터페이스를 구현하므로 클래스는 IEntityWithChangeTracker 또는 IEntityWithRelationships 인터페이스를 구현할 수 없습니다.

  • ProxyCreationEnabled 옵션을 true로 설정해야합니다.

다음 예제는 동적 프록시 엔티티 클래스입니다.

public partial class Course {

   public Course() {
      this.Enrollments = new HashSet<Enrollment>();
   }

   public int CourseID { get; set; }
   public string Title { get; set; }
   public int Credits { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

프록시 개체 만들기를 비활성화하려면 ProxyCreationEnabled 속성 값을 false로 설정합니다.

관계형 데이터베이스에서 관계는 외래 키를 통해 관계형 데이터베이스 테이블간에 존재하는 상황입니다. 외래 키 (FK)는 두 테이블의 데이터 간 연결을 설정하고 적용하는 데 사용되는 열 또는 열 조합입니다. 다음 다이어그램에는 세 개의 테이블이 있습니다.

  • Student
  • Course
  • Enrollment

위의 다이어그램에서 테이블 간의 일종의 연관성 / 관계를 볼 수 있습니다. 테이블 간에는 세 가지 유형의 관계가 있으며 서로 다른 테이블 간의 관계는 관련 열이 정의 된 방식에 따라 다릅니다.

  • 일대 다 관계
  • 다 대다 관계
  • 일대일 관계

일대 다 관계

  • 일대 다 관계는 가장 일반적인 관계 유형입니다.

  • 이 유형의 관계에서 테이블 A의 행은 테이블 B에서 일치하는 행을 많이 가질 수 있지만 테이블 B의 행은 테이블 A에서 일치하는 행을 하나만 가질 수 있습니다.

  • 외래 키는 관계의 많은 끝을 나타내는 테이블에 정의됩니다.

  • 예를 들어, 위의 다이어그램에서 Student 및 Enrollment 테이블에는 일대일 관계가 있고 각 학생은 여러 등록을 가질 수 있지만 각 등록은 한 학생에만 속합니다.

엔티티 프레임 워크에서 이러한 관계는 코드로도 생성 될 수 있습니다. 다음은 일대 다 관계와 관련된 학생 및 등록 클래스의 예입니다.

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

public class Enrollment {

   public int EnrollmentID { get; set; }
   public int CourseID { get; set; }
   public int StudentID { get; set; }
	
   public Grade? Grade { get; set; }
   public virtual Course Course { get; set; }
   public virtual Student Student { get; set; }
}

위의 코드에서 Student 클래스에는 Enrollment 컬렉션이 포함되어 있지만 Enrollment 클래스에는 단일 Student Object가 있음을 알 수 있습니다.

다 대다 관계

다 대다 관계에서 테이블 A의 행은 테이블 B에 일치하는 많은 행을 가질 수 있으며 그 반대의 경우도 마찬가지입니다.

  • 정션 테이블이라는 세 번째 테이블을 정의하여 이러한 관계를 만들 수 있습니다.이 테이블의 기본 키는 테이블 A와 테이블 B의 외래 키로 구성됩니다.

  • 예를 들어, Student 및 Course 테이블에는 이러한 각 테이블에서 Enrollment 테이블로의 일대 다 관계로 정의되는 다 대다 관계가 있습니다.

다음 코드에는 Course 클래스와 위의 두 클래스가 포함되어 있습니다. StudentEnrollment.

public class Course {
   [DatabaseGenerated(DatabaseGeneratedOption.None)]
	
   public int CourseID { get; set; }
   public string Title { get; set; }
	
   public int Credits { get; set; } 
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

Course 클래스와 Student 클래스에는 접합 클래스 등록을 통해 다 대다 관계를 만드는 Enrollment 개체 컬렉션이 있음을 알 수 있습니다.

일대일 관계

  • 일대일 관계에서 테이블 A의 행은 테이블 B에서 일치하는 행을 하나만 가질 수 있으며 그 반대의 경우도 마찬가지입니다.

  • 관련 열이 모두 기본 키이거나 고유 한 제약 조건이있는 경우 일대일 관계가 생성됩니다.

  • 일대일 관계에서 기본 키는 추가로 외래 키 역할을하며 두 테이블에 대해 별도의 외래 키 열이 없습니다.

이러한 방식으로 관련된 대부분의 정보가 모두 하나의 테이블에 있기 때문에 이러한 유형의 관계는 일반적이지 않습니다. 당신은 일대일 관계를 사용할 수 있습니다-

  • 열이 많은 테이블을 나눕니다.
  • 보안상의 이유로 테이블의 일부를 분리하십시오.
  • 수명이 짧고 테이블 삭제만으로 쉽게 삭제할 수있는 데이터를 저장합니다.
  • 기본 테이블의 하위 집합에만 적용되는 정보를 저장합니다.

다음 코드는 학생 이메일 ID와 비밀번호를 포함하는 다른 클래스 이름 StudentProfile을 추가하는 것입니다.

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
   public virtual StudentProfile StudentProfile { get; set; }
}

public class StudentProfile {

   public StudentProfile() {}
   public int ID { get; set; }
   public string Email { get; set; }
   public string Password { get; set; }
	
   public virtual Student Student { get; set; }
}

Student 엔터티 클래스에는 StudentProfile 탐색 속성이 포함되어 있고 StudentProfile에는 Student 탐색 속성이 포함되어 있음을 알 수 있습니다.

각 학생은 대학 도메인에 로그인 할 수있는 이메일과 비밀번호가 하나만 있습니다. 이러한 정보는 Student 테이블에 추가 할 수 있지만 보안상의 이유로 다른 테이블로 분리됩니다.

일생

컨텍스트의 수명은 인스턴스가 생성 될 때 시작되고 인스턴스가 삭제되거나 가비지 수집 될 때 끝납니다.

  • 컨텍스트 수명은 ORM을 사용할 때 내리는 매우 중요한 결정입니다.

  • 컨텍스트는 엔터티 캐시처럼 작동하므로로드 된 모든 엔터티에 대한 참조를 보유하고 있으며 이는 메모리 소비가 매우 빠르게 증가하고 메모리 누수를 유발할 수도 있음을 의미합니다.

  • 아래 다이어그램에서 컨텍스트를 통해 응용 프로그램에서 데이터베이스로 또는 그 반대로 데이터 워크 플로의 상위 수준을 볼 수 있습니다.

엔티티 라이프 사이클

엔티티 라이프 사이클은 엔티티가 생성, 추가, 수정, 삭제되는 프로세스를 설명합니다. 엔티티는 수명 동안 많은 상태를가집니다. 엔티티 상태를 검색하는 방법을보기 전에 엔티티 상태가 무엇인지 살펴 보겠습니다. 상태는 유형의 열거 형입니다.System.Data.EntityState 다음 값을 선언합니다-

  • Added: 엔티티가 추가됨으로 표시됩니다.

  • Deleted: 엔티티가 삭제 된 것으로 표시됩니다.

  • Modified: 엔티티가 수정되었습니다.

  • Unchanged: 엔티티가 수정되지 않았습니다.

  • Detached: 엔티티는 추적되지 않습니다.

엔터티 수명주기의 상태 변경

때때로 엔티티의 상태는 컨텍스트에 의해 자동으로 설정되지만 개발자가 수동으로 수정할 수도 있습니다. 한 상태에서 다른 상태로 전환하는 모든 조합이 가능하지만 일부는 의미가 없습니다. 예를 들면Added 엔티티에 Deleted 상태 또는 그 반대입니다.

다양한 상태에 대해 논의 해 봅시다.

변경되지 않은 상태

  • 엔터티가 변경되지 않은 경우 컨텍스트에 바인딩되지만 수정되지 않았습니다.

  • 기본적으로 데이터베이스에서 검색된 엔티티는이 상태입니다.

  • 엔티티가 컨텍스트에 첨부되면 (Attach 메서드 사용) 마찬가지로 Unchanged 상태가됩니다.

  • 컨텍스트는 참조하지 않는 개체의 변경 사항을 추적 할 수 없으므로 연결될 때 변경되지 않은 것으로 간주합니다.

분리 된 상태

  • 컨텍스트가 코드에서 개체의 생성을 추적 할 수 없기 때문에 분리는 새로 생성 된 엔터티의 기본 상태입니다.

  • 컨텍스트의 using 블록 내에서 엔티티를 인스턴스화하는 경우에도 마찬가지입니다.

  • 분리됨은 추적이 비활성화 된 경우 데이터베이스에서 검색된 엔티티의 상태도입니다.

  • 엔티티가 분리되면 컨텍스트에 바인딩되지 않으므로 해당 상태가 추적되지 않습니다.

  • 폐기, 수정, 다른 클래스와 함께 사용하거나 필요한 다른 방식으로 사용할 수 있습니다.

  • 컨텍스트 추적이 없기 때문에 Entity Framework에는 의미가 없습니다.

추가 된 상태

  • 엔티티가 추가됨 상태이면 옵션이 거의 없습니다. 실제로 컨텍스트에서 분리 할 수만 있습니다.

  • 당연히 일부 속성을 수정하더라도 Modified, Unchanged 또는 Deleted로 이동하는 것은 의미가 없기 때문에 상태는 Added로 유지됩니다.

  • 새 엔티티이며 데이터베이스의 행과 일치하지 않습니다.

  • 이는 이러한 상태 중 하나에있는 기본 전제 조건입니다 (그러나이 규칙은 컨텍스트에 의해 적용되지 않음).

수정 된 상태

  • 엔티티가 수정되면 이는 변경되지 않음 상태 였고 일부 속성이 변경되었음을 의미합니다.

  • 엔티티가 수정 됨 상태가되면 분리됨 또는 삭제됨 상태로 이동할 수 있지만 원래 값을 수동으로 복원하더라도 변경되지 않음 상태로 롤백 할 수 없습니다.

  • 이 ID를 가진 행이 이미 데이터베이스에 존재하고이를 지속 할 때 런타임 예외가 발생하므로 엔티티를 분리하고 컨텍스트에 추가하지 않는 한 추가됨으로 변경할 수도 없습니다.

삭제 된 상태

  • 엔터티는 변경되지 않았거나 수정 된 후 DeleteObject 메서드가 사용 되었기 때문에 삭제됨 상태가됩니다.

  • 이 상태에서 Detached 이외의 다른 값으로 무의미하게 변경되기 때문에 가장 제한적인 상태입니다.

그만큼 using컨텍스트가 제어하는 ​​모든 리소스를 블록의 끝에 배치하려면 문을 사용합니다. 당신이 사용할 때using 그런 다음 컴파일러는 try / finally 블록을 자동으로 생성하고 finally 블록에서 dispose를 호출합니다.

using (var context = new UniContext()) {

   var student = new Student {
      LastName = "Khan", 
      FirstMidName = "Ali", 
      EnrollmentDate = DateTime.Parse("2005-09-01")
   };

   context.Students.Add(student);
   context.SaveChanges();
}

장기 실행 컨텍스트로 작업 할 때 다음을 고려하십시오.

  • 더 많은 개체와 해당 참조를 메모리에로드하면 컨텍스트의 메모리 사용량이 빠르게 증가 할 수 있습니다. 이로 인해 성능 문제가 발생할 수 있습니다.

  • 더 이상 필요하지 않은 경우 컨텍스트를 처리해야합니다.

  • 예외로 인해 컨텍스트가 복구 불가능한 상태가되는 경우 전체 애플리케이션이 종료 될 수 있습니다.

  • 동시성 관련 문제가 발생할 가능성은 데이터를 쿼리하고 업데이트하는 시간 사이의 간격이 커짐에 따라 증가합니다.

  • 웹 애플리케이션으로 작업 할 때 요청 당 컨텍스트 인스턴스를 사용하십시오.

  • WPF (Windows Presentation Foundation) 또는 Windows Forms로 작업 할 때 양식당 컨텍스트 인스턴스를 사용합니다. 이를 통해 컨텍스트가 제공하는 변경 추적 기능을 사용할 수 있습니다.

경험의 규칙

Web Applications

  • 이제 웹 애플리케이션의 경우 요청 당 컨텍스트가 사용되는 것이 일반적이고 모범 사례입니다.

  • 웹 애플리케이션에서 우리는 매우 짧지 만 모든 서버 트랜잭션을 보유하는 요청을 처리하므로 컨텍스트가 유지되는 적절한 기간입니다.

Desktop Applications

  • Win Forms / WPF 등과 같은 데스크톱 응용 프로그램의 경우 컨텍스트는 양식 / 대화 상자 / 페이지별로 사용됩니다.

  • 컨텍스트를 애플리케이션의 싱글 톤으로 사용하고 싶지 않기 때문에 한 양식에서 다른 양식으로 이동할 때이를 처리합니다.

  • 이런 식으로 우리는 컨텍스트의 많은 능력을 얻고 장기 실행 컨텍스트의 영향을받지 않을 것입니다.

Entity Framework는 엔터티 모델을 만드는 세 가지 접근 방식을 제공하며 각 접근 방식에는 고유 한 장단점이 있습니다.

  • 코드 우선
  • 데이터베이스 우선
  • 먼저 모델

이 장에서는 코드 우선 접근 방식에 대해 간략하게 설명합니다. 일부 개발자는 코드에서 디자이너로 작업하는 것을 선호하는 반면 다른 개발자는 코드로 작업하는 것을 선호합니다. 이러한 개발자를 위해 Entity Framework에는 Code First라고하는 모델링 워크 플로가 있습니다.

  • Code First 모델링 워크 플로우는 존재하지 않는 데이터베이스를 대상으로하며 Code First가이를 생성합니다.

  • 데이터베이스가 비어있는 경우에도 사용할 수 있으며 Code First도 새 테이블을 추가합니다.

  • Code First를 사용하면 C # 또는 VB.Net 클래스를 사용하여 모델을 정의 할 수 있습니다.

  • 추가 구성은 클래스 및 속성의 속성을 사용하거나 유창한 API를 사용하여 선택적으로 수행 할 수 있습니다.

왜 코드 우선인가?

  • Code First는 실제로 퍼즐 조각 세트로 구성되어 있습니다. 첫 번째는 도메인 클래스입니다.

  • 도메인 클래스는 Entity Framework와 관련이 없습니다. 비즈니스 도메인의 항목 일뿐입니다.

  • 그러면 Entity Framework에는 이러한 클래스와 데이터베이스 간의 상호 작용을 관리하는 컨텍스트가 있습니다.

  • 컨텍스트는 Code First에만 국한되지 않습니다. Entity Framework 기능입니다.

  • Code First는 컨텍스트가 관리하는 클래스를 검사 한 다음 일련의 규칙 또는 규칙을 사용하여 해당 클래스와 관계가 모델을 설명하는 방법과 해당 모델이 데이터베이스에 매핑되는 방법을 결정하는 모델 빌더를 추가합니다.

  • 이 모든 것은 런타임에 발생합니다. 이 모델은 결코 볼 수 없으며 단지 메모리에 있습니다.

  • Code First는 필요한 경우 해당 모델을 사용하여 데이터베이스를 생성 할 수 있습니다.

  • Code First Migrations라는 기능을 사용하여 모델이 변경되면 데이터베이스를 업데이트 할 수도 있습니다.

이 장에서는 Model First라고하는 워크 플로를 사용하여 디자이너에서 엔터티 데이터 모델을 만드는 방법을 알아 봅니다.

  • Model First는 데이터베이스가 아직 존재하지 않는 새 프로젝트를 시작할 때 유용합니다.

  • 모델은 EDMX 파일에 저장되며 Entity Framework Designer에서보고 편집 할 수 있습니다.

  • Model First에서는 Entity Framework 디자이너에서 모델을 정의한 다음 SQL을 생성하여 모델과 일치하는 데이터베이스 스키마를 만든 다음 SQL을 실행하여 데이터베이스에 스키마를 만듭니다.

  • 애플리케이션에서 상호 작용하는 클래스는 EDMX 파일에서 자동으로 생성됩니다.

다음은 Model First 접근 방식을 사용하여 새 콘솔 프로젝트를 만드는 간단한 예입니다.

Step 1 − Visual Studio를 열고 파일 → 새로 만들기 → 프로젝트를 선택합니다.

Step 2 − 왼쪽 창에서 설치됨 → 템플릿 → Visual C # → Windows를 선택한 다음 가운데 창에서 콘솔 응용 프로그램을 선택합니다.

Step 3 − 이름 필드에 EFModelFirstDemo를 입력합니다.

Step 4 − 모델을 생성하려면 먼저 솔루션 탐색기에서 콘솔 프로젝트를 마우스 오른쪽 버튼으로 클릭하고 추가 → 새 항목…을 선택합니다.

다음 대화 상자가 열립니다.

Step 5 − 가운데 창에서 ADO.NET 엔티티 데이터 모델을 선택하고 이름 필드에 ModelFirstDemoDB 이름을 입력합니다.

Step 6 − Click Add button which will launch the Entity Data Model Wizard dialog.

Step 7 − Select Empty EF Designer model and click Next button. The Entity Framework Designer opens with a blank model. Now we can start adding entities, properties and associations to the model.

Step 8 − Right-click on the design surface and select Properties. In the Properties window, change the Entity Container Name to ModelFirstDemoDBContext.

Step 9 − Right-click on the design surface and select Add New → Entity…

Add Entity dialog will open as shown in the following image.

Step 10 − Enter Student as entity name and Student Id as property name and click Ok.

Step 11 − Right-click on the new entity on the design surface and select Add New → Scalar Property, enter Name as the name of the property.

Step 12 − Enter FirstName and then add another two scalar properties such as LastName and EnrollmentDate.

Step 13 − Add two more Entities Course and Enrollment by following all the steps mentioned above and also add some Scalar properties as shown in the following steps.

Step 14 − We have three entities in Visual Designer, let’s add some association or relationship between them.

Step 15 − Right-click on the design surface and select Add New → Association…

Step 16 − Make one end of the relationship point to Student with a multiplicity of one and the other end point to Enrollment with a multiplicity of many.

Step 17 − This means that a Student has many Enrollments and Enrollment belongs to one Student.

Step 18 − Ensure the Add foreign key properties to 'Post' Entity box is checked and click OK.

Step 19 − Similarly, add one more association between Course and Enrollment.

Step 20 − Your data model will look like the following screen after adding associations between entities.

We now have a simple model that we can generate a database from and use to read and write data. Let's go ahead and generate the database.

Step 1 − Right-click on the design surface and select Generate Database from Model…

Step 2 − You can select existing database or create a new connection by clicking on New Connection…

Step 3 − To create new Database, click on New Connection…

Step 4 − Enter Server name and database name.

Step 5 − Click Next.

Step 6 − Click Finish. This will add *.edmx.sql file in the project. You can execute DDL scripts in Visual Studio by opening .sql file, then right-click and select Execute.

Step 7 − The following dialog will be displayed to connect to database.

Step 8 − On successful execution, you will see the following message.

Step 9 − 서버 탐색기로 이동하면 지정된 세 개의 테이블로 데이터베이스가 생성 된 것을 볼 수 있습니다.

다음으로 DbContext API를 사용하는 코드를 생성하기 위해 모델을 교체해야합니다.

Step 1 − EF 디자이너에서 모델의 빈 부분을 마우스 오른쪽 버튼으로 클릭하고 코드 생성 항목 추가…를 선택합니다.

다음 새 항목 추가 대화 상자가 열립니다.

Step 2 − 가운데 창에서 EF 6.x DbContext Generator를 선택하고 이름 필드에 ModelFirstDemoModel을 입력합니다.

Step 3 − 솔루션 탐색기에서 ModelFirstDemoModel.Context.tt 및 ModelFirstDemoModel.tt 템플릿이 생성 된 것을 볼 수 있습니다.

ModelFirstDemoModel.Context는 DbCcontext 및 컨텍스트, 학생 및 과정 등과 같이 쿼리에 반환하고 사용할 수있는 개체 집합을 생성합니다.

다른 템플릿은 Student, Courses 등의 모든 유형을 다룹니다. 다음은 엔티티 모델에서 자동으로 생성되는 Student 클래스입니다.

다음은 데이터베이스에서 일부 데이터를 입력하고 검색하는 C # 코드입니다.

using System;
using System.Linq;

namespace EFModelFirstDemo {

   class Program {

      static void Main(string[] args) {

         using (var db = new ModelFirstDemoDBContext()) {

            // Create and save a new Student

            Console.Write("Enter a name for a new Student: ");
            var firstName = Console.ReadLine();

            var student = new Student {
               StudentID = 1,
               FirstName = firstName
            };
				
            db.Students.Add(student);
            db.SaveChanges();
				
            var query = from b in db.Students
               orderby b.FirstName select b;

            Console.WriteLine("All student in the database:");

            foreach (var item in query) {
               Console.WriteLine(item.FirstName);
            }

            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
         }
      }
   }
}

위의 코드가 실행되면 다음과 같은 출력을 받게됩니다.

Enter a name for a new Student:
Ali Khan
All student in the database:
Ali Khan
Press any key to exit...

더 나은 이해를 위해 위의 예를 단계별로 실행하는 것이 좋습니다.

이 장에서는 Database First 접근 방식으로 엔터티 데이터 모델을 만드는 방법에 대해 알아 보겠습니다.

  • Database First Approach는 엔터티 데이터 모델에 대한 Code First 및 Model First 접근법에 대한 대안을 제공합니다. 프로젝트의 데이터베이스에서 모델 코드 (클래스, 속성, DbContext 등)를 생성하고 이러한 클래스는 데이터베이스와 컨트롤러 사이의 링크가됩니다.

  • Database First Approach는 기존 데이터베이스에서 엔티티 프레임 워크를 생성합니다. Model First 접근 방식에서 사용한 것과 동일한 방식으로 모델 / 데이터베이스 동기화 및 코드 생성과 같은 다른 모든 기능을 사용합니다.

간단한 예를 들어 보겠습니다. 다음 이미지와 같이 3 개의 테이블이 포함 된 데이터베이스가 이미 있습니다.

Step 1 − DatabaseFirstDemo 이름으로 새 콘솔 프로젝트를 생성 해 보겠습니다.

Step 2 − 모델을 생성하려면 먼저 솔루션 탐색기에서 콘솔 프로젝트를 마우스 오른쪽 버튼으로 클릭하고 추가 → 새 항목…을 선택합니다.

Step 3 − 중간 창에서 ADO.NET 엔티티 데이터 모델을 선택하고 이름 필드에 DatabaseFirstModel 이름을 입력합니다.

Step 4 − 추가 버튼을 클릭하면 엔티티 데이터 모델 마법사 대화 상자가 시작됩니다.

Step 5 − 데이터베이스에서 EF 디자이너를 선택하고 다음 버튼을 클릭합니다.

Step 6 − 기존 데이터베이스를 선택하고 다음을 클릭합니다.

Step 7 − Entity Framework 6.x를 선택하고 다음을 클릭합니다.

Step 8 − 포함하려는 모든 테이블보기 및 저장 프로 시저를 선택하고 마침을 클릭합니다.

엔티티 모델 및 POCO 클래스가 데이터베이스에서 생성 된 것을 볼 수 있습니다.

이제 program.cs 파일에 다음 코드를 작성하여 데이터베이스에서 모든 학생을 검색해 보겠습니다.

using System;
using System.Linq;

namespace DatabaseFirstDemo {

   class Program {

      static void Main(string[] args) {

         using (var db = new UniContextEntities()) {

            var query = from b in db.Students
               orderby b.FirstMidName select b;

            Console.WriteLine("All All student in the database:");

            foreach (var item in query) {
               Console.WriteLine(item.FirstMidName +" "+ item.LastName);
            }

            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
         }
      }
   }
}

위의 프로그램이 실행되면 다음과 같은 출력을 받게됩니다.

All student in the database:
Ali Khan
Arturo   finand
Bill Gates
Carson Alexander
Gytis Barzdukas
Laura Norman
Meredith Alonso
Nino Olivetto
Peggy Justice
Yan Li
Press any key to exit...

위의 프로그램이 실행되면 이전에 데이터베이스에 입력 된 모든 학생의 이름이 표시됩니다.

더 나은 이해를 위해 위의 예를 단계별로 실행하는 것이 좋습니다.

이 장에서는 Designer 또는 Database First를 사용하거나 Code First를 사용하여 모델을 작성하는 데 중점을 둡니다. 다음은 선택할 모델링 워크 플로를 결정하는 데 도움이되는 몇 가지 지침입니다.

  • Code First 모델링, Database First 모델링 및 Model First 모델링 워크 플로의 예를 이미 살펴 보았습니다.

  • Database First 및 Model First 워크 플로는 Designer를 사용했지만 하나는 데이터베이스로 시작하여 모델을 만들고 다른 하나는 모델에서 시작하여 데이터베이스를 만듭니다.

  • Visual Designer와 코드 생성을 사용하지 않으려는 개발자를 위해 Entity Framework에는 Code First라는 완전히 다른 워크 플로가 있습니다.

  • Code First의 일반적인 워크 플로는 데이터베이스가없는 새로운 애플리케이션에 적합합니다. 클래스와 코드를 정의한 다음 Code First가 데이터베이스의 모양을 파악하도록합니다.

  • 데이터베이스로 Code First를 시작할 수도 있으며 이는 Code First를 약간 모순으로 만듭니다. 그러나 데이터베이스를 클래스로 리버스 엔지니어링 할 수있는 도구가 있습니다. 이는 코딩을 시작하는 좋은 방법입니다.

이러한 옵션이 주어지면 의사 결정 트리를 살펴 보겠습니다.

  • 생성 된 코드에서 Visual Designer로 작업하려는 경우 EF Designer와 관련된 워크 플로 중 하나를 선택하는 것이 좋습니다. 데이터베이스가 이미있는 경우 Database First가 경로입니다.

  • 데이터베이스가없는 새로운 프로젝트에서 Visual Designer를 사용하려는 경우 Model First를 사용하는 것이 좋습니다.

  • 디자이너가 아닌 코드로 작업하고 싶다면 Code First가 아마도 데이터베이스를 클래스로 리버스 엔지니어링하는 도구를 사용하는 옵션과 함께 당신을위한 것입니다.

  • 기존 클래스가있는 경우 가장 좋은 방법은 Code First와 함께 사용하는 것입니다.

이전 장에서 엔티티 데이터 모델을 정의하는 세 가지 방법을 배웠습니다.

  • 그 중 두 가지 인 Database First와 Model First는 코드 생성과 결합 된 Entity Framework 디자이너에 의존했습니다.

  • 세 번째 인 Code First는 비주얼 디자이너를 건너 뛰고 자신 만의 코드를 작성할 수 있도록합니다.

  • 선택하는 경로에 관계없이 도메인 클래스로 끝나고 하나 이상의 Entity Framework DbContext 클래스를 사용하여 해당 클래스와 관련된 데이터를 검색하고 유지할 수 있습니다.

애플리케이션의 DbContext API는 클래스와 데이터베이스 간의 브리지로 사용됩니다. DbContext는 Entity Framework에서 가장 중요한 클래스 중 하나입니다.

  • 쿼리를 표현하고 실행할 수 있습니다.

  • 데이터베이스에서 쿼리 결과를 가져와 모델 클래스의 인스턴스로 변환합니다.

  • 추가 및 삭제를 포함하여 엔터티의 변경 사항을 추적 한 다음 요청시 데이터베이스로 전송되는 삽입, 업데이트 및 삭제 문 생성을 트리거 할 수 있습니다.

다음은이 장에서 다른 작업을 수행 할 도메인 광고 컨텍스트 클래스입니다. 이것은 Database First Approach에서 만든 것과 동일한 예제입니다.

컨텍스트 클래스 구현

using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Core.Objects;
using System.Linq;

namespace DatabaseFirstDemo {

   public partial class UniContextEntities : DbContext {

      public UniContextEntities(): base("name = UniContextEntities") {}

      protected override void OnModelCreating(DbModelBuilder modelBuilder) {
         throw new UnintentionalCodeFirstException();
      }

      public virtual DbSet<Course> Courses { get; set; }
      public virtual DbSet<Enrollment> Enrollments { get; set; }
      public virtual DbSet<Student> Students { get; set; }
   }
}

도메인 클래스 구현

코스 클래스

namespace DatabaseFirstDemo {

   using System;
   using System.Collections.Generic;
	
   public partial class Course {

      [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", 
         "CA2214:DoNotCallOverridableMethodsInConstructors")]

      public Course() {
         this.Enrollments = new HashSet<Enrollment>();
      }
	
      public int CourseID { get; set; }
      public string Title { get; set; }
      public int Credits { get; set; }
	
      [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", 
         "CA2227:CollectionPropertiesShouldBeReadOnly")]
			
      public virtual ICollection<Enrollment> Enrollments { get; set; }
   }
}

학생 수업

namespace DatabaseFirstDemo {

   using System;
   using System.Collections.Generic; 

   public partial class Student {

      [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", 
         "CA2214:DoNotCallOverridableMethodsInConstructors")]

      public Student() {
         this.Enrollments = new HashSet<Enrollment>();
      }

      public int ID { get; set; }
      public string LastName { get; set; }
      public string FirstMidName { get; set; }
      public System.DateTime EnrollmentDate { get; set; }

      [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", 
         "CA2227:CollectionPropertiesShouldBeReadOnly")]
			
      public virtual ICollection<Enrollment> Enrollments { get; set; }
   }
}

등록 클래스

namespace DatabaseFirstDemo {

   using System;
   using System.Collections.Generic; 

   public partial class Enrollment {

      public int EnrollmentID { get; set; }
      public int CourseID { get; set; }
      public int StudentID { get; set; }
      public Nullable<int> Grade { get; set; }
		
      public virtual Course Course { get; set; }
      public virtual Student Student { get; set; }
   }
}

작업 생성

Entity Framework를 사용하여 새 개체를 추가하는 것은 개체의 새 인스턴스를 생성하고 DbSet에서 Add 메서드를 사용하여 등록하는 것처럼 간단합니다. 다음 코드를 사용하면 새 학생을 데이터베이스에 추가 할 수 있습니다.

class Program {

   static void Main(string[] args) {

      var newStudent = new Student();

      //set student name

      newStudent.FirstMidName = "Bill";
      newStudent.LastName = "Gates";
      newStudent.EnrollmentDate = DateTime.Parse("2015-10-21");
      newStudent.ID = 100;

      //create DBContext object

      using (var dbCtx = new UniContextEntities()) {

         //Add Student object into Students DBset
         dbCtx.Students.Add(newStudent);

         // call SaveChanges method to save student into database
         dbCtx.SaveChanges();
      }
   }
}

업데이트 작업

기존 객체를 변경하는 것은 변경하려는 속성에 할당 된 값을 업데이트하고 SaveChanges를 호출하는 것만 큼 간단합니다. 예를 들어 다음 코드는 Ali의 성을 Khan에서 Aslam으로 변경하는 데 사용됩니다.

using (var context = new UniContextEntities()) {

   var student = (from d in context.Students where d.FirstMidName == "Ali" select d).Single();
   student.LastName = "Aslam";
   context.SaveChanges();
}

작업 삭제

Entity Framework를 사용하여 엔터티를 삭제하려면 DbSet에서 Remove 메서드를 사용합니다. 제거는 기존 및 새로 추가 된 엔티티 모두에 대해 작동합니다. 추가되었지만 아직 데이터베이스에 저장되지 않은 엔티티에 대해 Remove를 호출하면 엔티티 추가가 취소됩니다. 엔티티가 변경 추적기에서 제거되고 더 이상 DbContext에 의해 추적되지 않습니다. 변경 추적중인 기존 엔티티에 대해 Remove를 호출하면 다음에 SaveChanges가 호출 될 때 삭제할 엔티티가 등록됩니다. 다음 예제는 이름이 Ali 인 데이터베이스에서 학생이 제거 된 코드입니다.

using (var context = new UniContextEntities()) {
   var bay = (from d in context.Students where d.FirstMidName == "Ali" select d).Single();
   context.Students.Remove(bay);
   context.SaveChanges();
}

읽기 작업

데이터베이스에서 기존 데이터를 읽는 것은 매우 간단합니다. 다음은 Student 테이블에서 모든 데이터를 검색 한 다음 알파벳 순서로 학생의 성과 이름과 함께 프로그램이 표시되는 코드입니다.

using (var db = new UniContextEntities()) {

   var query = from b in db.Students orderby b.FirstMidName select b;
   Console.WriteLine("All All student in the database:");

   foreach (var item in query) {
      Console.WriteLine(item.FirstMidName +" "+ item.LastName);
   }

   Console.WriteLine("Press any key to exit...");
   Console.ReadKey();
}

데이터 액세스 개발자는 데이터 동시성에 관한 질문에 "한 사람 이상이 동시에 동일한 데이터를 편집하면 어떻게됩니까?"라는 질문에 답하는 데 어려움을 겪습니다.

  • 우리 중 운이 좋을수록 "문제 없음, 마지막 승리"라는 비즈니스 규칙을 처리합니다.

  • 이 경우 동시성은 문제가되지 않습니다. 아마도 그렇게 간단하지 않으며 모든 시나리오를 한 번에 해결할 수있는 은색 총알도 없습니다.

  • 기본적으로 Entity Framework는 "최근의 성공"경로를 사용합니다. 즉, 데이터가 검색된 시간과 데이터가 저장된 시간 사이에 다른 사람이 데이터를 업데이트 한 경우에도 최신 업데이트가 적용됩니다.

더 잘 이해하기 위해 예를 들어 보겠습니다. 다음 예에서는 Course 테이블에 새 열 VersionNo를 추가합니다.

디자이너로 이동하여 디자이너 창을 마우스 오른쪽 버튼으로 클릭하고 데이터베이스에서 모델 업데이트…를 선택합니다.

코스 항목에 다른 열이 추가 된 것을 볼 수 있습니다.

새로 생성 된 VersionNo 열을 마우스 오른쪽 단추로 클릭하고 속성을 선택하고 다음 이미지와 같이 ConcurrencyMode를 고정으로 변경합니다.

Course.VersionNo의 ConcurrencyMode를 Fixed로 설정하면 과정이 업데이트 될 때마다 업데이트 명령이 EntityKey 및 VersionNo 속성을 사용하여 과정을 찾습니다.

간단한 시나리오를 살펴 보겠습니다. 두 명의 사용자가 동시에 동일한 코스를 검색하고 사용자 1은 해당 코스의 제목을 Maths로 변경하고 사용자 2 이전에 변경 사항을 저장합니다. 나중에 사용자 2가 사용자 1이 자신의 변경 사항을 저장하기 전에 검색된 해당 코스의 제목을 변경하면 케이스 사용자 2는 동시성 예외를 받게됩니다."User2: Optimistic Concurrency exception occured".

using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;

namespace DatabaseFirstDemo {

   class Program {

      static void Main(string[] args) {

         Course c1 = null;
         Course c2 = null;

         //User 1 gets Course

         using (var context = new UniContextEntities()) {
            context.Configuration.ProxyCreationEnabled = false;
            c1 = context.Courses.Where(s ⇒ s.CourseID == 1).Single();
         }

         //User 2 also get the same Course

         using (var context = new UniContextEntities()) {
            context.Configuration.ProxyCreationEnabled = false;
            c2 = context.Courses.Where(s ⇒ s.CourseID == 1).Single();
         }

         //User 1 updates Course Title
         c1.Title = "Edited from user1";

         //User 2 updates Course Title
         c2.Title = "Edited from user2";

         //User 1 saves changes first

         using (var context = new UniContextEntities()) {

            try {
               context.Entry(c1).State = EntityState.Modified;
               context.SaveChanges();
            } catch (DbUpdateConcurrencyException ex) {
               Console.WriteLine("User1: Optimistic Concurrency exception occurred");
            }
         }

         //User 2 saves changes after User 1.
         //User 2 will get concurrency exection
         //because CreateOrModifiedDate is different in the database

         using (var context = new UniContextEntities()) {

            try {
               context.Entry(c2).State = EntityState.Modified;
               context.SaveChanges();
            } catch (DbUpdateConcurrencyException ex) {
               Console.WriteLine("User2: Optimistic Concurrency exception occurred");
            }
         }
      }
   }
}

모든 버전의 Entity Framework에서 실행할 때마다 SaveChanges()데이터베이스를 삽입, 업데이트 또는 삭제하기 위해 프레임 워크는 트랜잭션에서 해당 작업을 래핑합니다. SaveChanges를 호출하면 컨텍스트가 자동으로 트랜잭션을 시작하고 지속성 성공 여부에 따라 트랜잭션을 커밋하거나 롤백합니다.

  • 이것은 모두 여러분에게 투명하며 처리 할 필요가 없습니다.

  • 이 트랜잭션은 작업을 실행하고 완료 할 수있을만큼만 지속됩니다.

  • 다른 작업을 실행하면 새 트랜잭션이 시작됩니다.

Entity Framework 6은 다음을 제공합니다.

Database.BeginTransaction ()

  • 사용자를위한 트랜잭션을 시작하고 완료하는 기존 DbContext 내에서 간단하고 쉬운 방법입니다.

  • 동일한 트랜잭션 내에서 여러 작업을 결합 할 수 있으므로 모두 커밋되거나 모두 하나로 롤백됩니다.

  • 또한 사용자가 트랜잭션에 대한 격리 수준을보다 쉽게 ​​지정할 수 있습니다.

Database.UseTransaction ()

  • 이를 통해 DbContext가 Entity Framework 외부에서 시작된 트랜잭션을 사용할 수 있습니다.

단일 트랜잭션에서 여러 작업이 수행되는 다음 예제를 살펴 보겠습니다. 코드는-

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         using (var dbContextTransaction = context.Database.BeginTransaction()) {

            try {

               Student student = new Student() {
                  ID = 200, 
                  FirstMidName = "Ali", 
                  LastName = "Khan", 
                  EnrollmentDate = DateTime.Parse("2015-12-1")
               };

               context.Students.Add(student);

               context.Database.ExecuteSqlCommand(@"UPDATE Course SET Title = 
                  'Calculus'" + "WHERE CourseID = 1045");

               var query = context.Courses.Where(c ⇒ c.CourseID == 1045);

               foreach (var item in query) {
                  Console.WriteLine(item.CourseID.ToString()
                     + " " + item.Title + " " + item.Credits);
               }

               context.SaveChanges();
               var query1 = context.Students.Where(s ⇒ s.ID == 200);

               foreach (var item in query1) {
                  Console.WriteLine(item.ID.ToString() 
                     + " " + item.FirstMidName + " " + item.LastName);
               }

               dbContextTransaction.Commit();
            } catch (Exception) {
               dbContextTransaction.Rollback();
            }

         }
      }
   }
}
  • 트랜잭션을 시작하려면 기본 저장소 연결이 열려 있어야합니다.

  • 따라서 Database.BeginTransaction ()을 호출하면 연결이 아직 열리지 않은 경우 열립니다.

  • DbContextTransaction이 연결을 연 경우 Dispose ()가 호출 될 때 연결이 닫힙니다.

뷰는 미리 정의 된 쿼리로 얻은 데이터를 포함하는 개체입니다. 뷰는 결과 집합이 쿼리에서 파생 된 가상 개체 또는 테이블입니다. 데이터 열과 행을 포함하므로 실제 테이블과 매우 유사합니다. 다음은보기의 일반적인 용도입니다.

  • 기본 테이블의 데이터 필터링
  • 보안 목적으로 데이터 필터링
  • 여러 서버에 분산 된 데이터를 중앙 집중화
  • 재사용 가능한 데이터 세트 만들기

뷰는 테이블을 사용할 수있는 것과 비슷한 방식으로 사용할 수 있습니다. 보기를 엔티티로 사용하려면 먼저 데이터베이스보기를 EDM에 추가해야합니다. 모델에 뷰를 추가 한 후 생성, 업데이트 및 삭제 작업을 제외하고 일반 엔터티와 동일한 방식으로 작업 할 수 있습니다.

데이터베이스에서 모델에 뷰를 추가하는 방법을 살펴 보겠습니다.

Step 1 − 새 콘솔 응용 프로그램 프로젝트를 생성합니다.

Step 2 − 솔루션 탐색기에서 프로젝트를 마우스 오른쪽 버튼으로 클릭하고 추가 → 새 항목을 선택합니다.

Step 3 − 중간 창에서 ADO.NET Entity Data Model을 선택하고 이름 필드에 ViewModel 이름을 입력합니다.

Step 4 − 추가 버튼을 클릭하면 엔티티 데이터 모델 마법사 대화 상자가 시작됩니다.

Step 5 − 데이터베이스에서 EF 디자이너를 선택하고 다음 버튼을 클릭합니다.

Step 6 − 기존 데이터베이스를 선택하고 다음을 클릭합니다.

Step 7 − Entity Framework 6.x를 선택하고 다음을 클릭합니다.

Step 8 − 데이터베이스에서 테이블과 뷰를 선택하고 마침을 클릭합니다.

뷰가 생성 된 것을 디자이너 창에서 볼 수 있으며 프로그램에서 엔티티로 사용할 수 있습니다.

솔루션 탐색기에서 MyView 클래스도 데이터베이스에서 생성 된 것을 볼 수 있습니다.

모든 데이터가 뷰에서 검색되는 예를 들어 보겠습니다. 다음은 코드입니다-

class Program {

   static void Main(string[] args) {

      using (var db = new UniContextEntities()) {

         var query = from b in db.MyViews
            orderby b.FirstMidName select b;

         Console.WriteLine("All student in the database:");

         foreach (var item in query) {
            Console.WriteLine(item.FirstMidName + " " + item.LastName);
         }

         Console.WriteLine("Press any key to exit...");
         Console.ReadKey();
      }
   }
}

위의 코드가 실행되면 다음과 같은 출력을 받게됩니다.

All student in the database:
Ali Khan
Arturo   finand
Bill Gates
Carson Alexander
Gytis Barzdukas
Laura Norman
Meredith Alonso
Nino Olivetto
Peggy Justice
Yan Li
Press any key to exit...

더 나은 이해를 위해 위의 예를 단계별로 실행하는 것이 좋습니다.

인덱스는 테이블과 뷰를 기반으로하는 온 디스크 데이터 구조입니다. 인덱스를 사용하면 대부분의 경우 데이터를 더 빠르고 효율적으로 검색 할 수 있습니다. 그러나 인덱스가있는 테이블 또는 뷰를 오버로드하면 삽입 또는 업데이트와 같은 다른 작업의 성능에 좋지 않은 영향을 미칠 수 있습니다.

  • 인덱싱은 데이터베이스에서 데이터를 쿼리하는 데 필요한 시간을 줄여 Code First 애플리케이션의 성능을 향상시킬 수있는 엔티티 프레임 워크의 새로운 기능입니다.

  • 다음을 사용하여 데이터베이스에 색인을 추가 할 수 있습니다. Index 속성 및 기본값 재정의 UniqueClustered 시나리오에 가장 적합한 인덱스를 얻기위한 설정.

CourseID의 Course 클래스에 Index 속성이 추가 된 다음 코드를 살펴 보겠습니다.

public partial class Course {

   public Course() {
      this.Enrollments = new HashSet<Enrollment>();
   }

   [Index]
   public int CourseID { get; set; }
   public string Title { get; set; }
	
   public int Credits { get; set; }
   public byte[] VersionNo { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }

}

위에서 생성 된 키는 고유하지 않고 클러스터되지 않습니다. 이러한 기본값을 재정의 할 수있는 과부하가 있습니다.

  • 인덱스를 클러스터형 인덱스로 만들려면 IsClustered = true를 지정해야합니다.

  • 마찬가지로 IsUnique = true를 지정하여 인덱스를 고유 인덱스로 만들 수도 있습니다.

인덱스가 클러스터되고 고유 한 다음 C # 코드를 살펴 보겠습니다.

public partial class Course {

   public Course() {
      this.Enrollments = new HashSet<Enrollment>();
   }

   [Index(IsClustered = true, IsUnique = true)]
   public int CourseID { get; set; }
   public string Title { get; set; }
	
   public int Credits { get; set; }
   public byte[] VersionNo { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

인덱스 속성을 사용하여 데이터베이스에서 고유 한 인덱스를 만들 수 있습니다. 그러나 이것은 EF가 관계 등을 다룰 때 열의 고유성을 추론 할 수 있다는 것을 의미하지는 않습니다.이 기능은 일반적으로 "고유 제약"에 대한 지원이라고합니다.

Entity Framework를 사용하면 자동 명령 생성 대신 또는 이와 함께 엔터티 데이터 모델의 저장 프로 시저를 사용할 수 있습니다.

  • 저장 프로 시저를 사용하여 데이터베이스 테이블에서 미리 정의 된 논리를 수행 할 수 있으며 많은 조직에는 이러한 저장 프로 시저를 사용해야하는 정책이 있습니다.

  • 또한 EF가 엔터티를 삽입, 업데이트 또는 삭제하는 데 저장 프로 시저를 사용하도록 지정할 수도 있습니다.

  • 동적으로 빌드 된 명령은 안전하고 효율적이며 일반적으로 사용자가 직접 작성할 수있는 것만큼이나 우수하지만 저장 프로 시저가 이미 존재하고 회사 관행이 테이블의 직접 사용을 제한 할 수있는 경우가 많습니다.

  • 또는 저장소에서 실행되는 작업을 명시 적으로 제어하고 저장 프로 시저를 만드는 것을 선호 할 수도 있습니다.

다음 예제는 파일 → 새로 만들기 → 프로젝트에서 새 프로젝트를 만듭니다.

Step 1 − 중간 창에서 콘솔 애플리케이션을 선택하고 이름 필드에 StoredProceduresDemo를 입력합니다.

Step 2 − 서버 탐색기에서 데이터베이스를 마우스 오른쪽 버튼으로 클릭합니다.

Step 3 − 새 쿼리를 선택하고 T-SQL 편집기에 다음 코드를 입력하여 데이터베이스에 새 테이블을 추가합니다.

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = 
   OBJECT_ID(N'[dbo].[StudentGrade]') AND type in (N'U'))

BEGIN

   CREATE TABLE [dbo].[StudentGrade](

      [EnrollmentID] [int] IDENTITY(1,1) NOT NULL,
      [CourseID] [int] NOT NULL,
      [StudentID] [int] NOT NULL,
      [Grade] [decimal](3, 2) NULL,

      CONSTRAINT [PK_StudentGrade] PRIMARY KEY CLUSTERED (
         [EnrollmentID] ASC
      )

      WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]

   ) ON [PRIMARY]

END
GO

Step 4 − 편집기를 마우스 오른쪽 버튼으로 클릭하고 실행을 선택합니다.

Step 5− 데이터베이스를 마우스 오른쪽 버튼으로 클릭하고 새로 고침을 클릭합니다. 데이터베이스에 새로 추가 된 테이블이 표시됩니다.

Step 6 − 서버 탐색기에서 데이터베이스를 다시 마우스 오른쪽 버튼으로 클릭합니다.

Step 7 − 새 쿼리를 선택하고 T-SQL 편집기에 다음 코드를 입력하여 데이터베이스에 저장 프로 시저를 추가하면 학생 성적이 반환됩니다.

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = 
   OBJECT_ID(N'[dbo].[GetStudentGrades]') AND type in (N'P', N'PC'))

BEGIN

   EXEC dbo.sp_executesql @statement = N'
   CREATE PROCEDURE [dbo].[GetStudentGrades]
   @StudentID int
   AS
   SELECT EnrollmentID, Grade, CourseID, StudentID FROM dbo.StudentGrade 
   WHERE StudentID = @StudentID
   '
END
GO

Step 8 − 편집기를 마우스 오른쪽 버튼으로 클릭하고 실행을 선택합니다.

Step 9− 데이터베이스를 마우스 오른쪽 버튼으로 클릭하고 새로 고침을 클릭합니다. 데이터베이스에 저장 프로 시저가 생성 된 것을 볼 수 있습니다.

Step 10 − 솔루션 탐색기에서 프로젝트 이름을 마우스 오른쪽 버튼으로 클릭하고 추가 → 새 항목을 선택합니다.

Step 11 − 그런 다음 템플릿 창에서 ADO.NET 엔티티 데이터 모델을 선택합니다.

Step 12 − 이름으로 SPModel을 입력하고 추가를 클릭합니다.

Step 13 − 모델 콘텐츠 선택 대화 상자에서 데이터베이스에서 EF 디자이너를 선택하고 다음을 클릭합니다.

Step 14 − 데이터베이스를 선택하고 다음을 클릭합니다.

Step 15 − 데이터베이스 개체 선택 대화 상자에서 테이블,보기를 클릭합니다.

Step 16 − Stored Procedures and Functions 노드 아래에있는 GetStudentGradesForCourse 함수를 선택하고 Finish를 클릭합니다.

Step 17 −보기 → 다른 창 → 엔터티 데이터 모델 브라우저를 선택하고 함수 가져 오기에서 GetStudentGrades를 마우스 오른쪽 버튼으로 클릭하고 편집을 선택합니다.

다음 대화 상자가 생성됩니다.

Step 18 − Entities 라디오 버튼을 클릭하고이 저장 프로 시저의 반환 유형으로 콤보 상자에서 StudentGrade를 선택하고 Ok를 클릭합니다.

GetStudentGrades 저장 프로 시저에서 매개 변수로 학생 ID를 전달하여 모든 성적을 검색하는 다음 C # 코드를 살펴 보겠습니다.

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         int studentID = 22;
         var studentGrades = context.GetStudentGrades(studentID);

         foreach (var student in studentGrades) {
            Console.WriteLine("Course ID: {0}, Title: {1}, Grade: {2} ", 
               student.CourseID, student.Course.Title, student.Grade);
         }

         Console.ReadKey();

      }
   }
}

위의 코드가 컴파일되고 실행되면 다음과 같은 출력을 받게됩니다.

Course ID: 4022, Title: Microeconomics, Grade: 3.00
Course ID: 4041, Title: Macroeconomics, Grade: 3.50

더 나은 이해를 위해 위의 예를 단계별로 실행하는 것이 좋습니다.

이 장에서는 컨텍스트에 의해 추적되지 않는 엔티티를 변경하는 방법을 살펴 보겠습니다. 컨텍스트에 의해 추적되지 않는 엔티티를 '연결 해제 된'엔티티라고합니다.

  • 사용자 인터페이스와 데이터베이스 액세스 계층이 동일한 애플리케이션 프로세스에서 실행되는 대부분의 단일 계층 애플리케이션의 경우 컨텍스트에 의해 추적되는 엔터티에 대해 작업을 수행 할 것입니다.

  • 연결이 끊어진 엔터티에 대한 작업은 N-Tier 애플리케이션에서 훨씬 더 일반적입니다.

  • N-Tier 응용 프로그램에는 서버에서 일부 데이터를 가져와 네트워크를 통해 클라이언트 컴퓨터로 반환하는 작업이 포함됩니다.

  • 그런 다음 클라이언트 응용 프로그램은이 데이터를 서버로 반환하기 전에 조작하여 유지합니다.

다음은 연결이 끊어진 엔터티 그래프 또는 연결이 끊어진 단일 엔터티로 수행해야하는 두 단계입니다.

  • 새 컨텍스트 인스턴스와 함께 엔티티를 연결하고 이러한 엔티티에 대해 컨텍스트를 인식합니다.

  • 이러한 엔터티에 적절한 EntityStates를 수동으로 설정합니다.

두 개의 Enrollment 엔터티와 함께 ​​Student 엔터티가 추가 된 다음 코드를 살펴 보겠습니다.

class Program {

   static void Main(string[] args) {

      var student = new Student {

         ID = 1001,
         FirstMidName = "Wasim",
         LastName = "Akram", 

         EnrollmentDate = DateTime.Parse("2015-10-10"), 
            Enrollments = new List<Enrollment> {

               new Enrollment{EnrollmentID = 2001,CourseID = 4022, StudentID = 1001 },
               new Enrollment{EnrollmentID = 2002,CourseID = 4025, StudentID = 1001 },
         }
      };

      using (var context = new UniContextEntities()) {

         context.Students.Add(student);
         Console.WriteLine("New Student ({0} {1}): {2}", 
            student.FirstMidName, student.LastName, context.Entry(student).State);

         foreach (var enrollment in student.Enrollments) {
            Console.WriteLine("Enrollment ID: {0} State: {1}", 
               enrollment.EnrollmentID, context.Entry(enrollment).State);
         }

         Console.WriteLine("Press any key to exit...");
         Console.ReadKey();
      }
   } 
}
  • 이 코드는 Enrollments 속성에서 두 개의 새 Enrollment 인스턴스를 참조하는 새 Student 인스턴스를 생성합니다.

  • 그런 다음 Add 메서드를 사용하여 새 Student가 컨텍스트에 추가됩니다.

  • Student가 추가되면 코드는 DbContext.Entry 메서드를 사용하여 Entity Framework가 새 Student에 대해 가지고있는 변경 내용 추적 정보에 액세스합니다.

  • 이 변경 내용 추적 정보에서 State 속성은 엔터티의 현재 상태를 작성하는 데 사용됩니다.

  • 그런 다음 새 학생에서 참조하는 새로 생성 된 각 등록에 대해이 프로세스가 반복됩니다. 응용 프로그램을 실행하면 다음 출력이 표시됩니다.

New Student   (Wasim  Akram): Added
Enrollment ID: 2001 State: Added
Enrollment ID: 2002 State: Added
Press any key to exit...

DbSet.Add는 Entity Framework에 새 엔터티에 대해 알리는 데 사용되지만 DbSet.Attach는 Entity Framework에 기존 엔터티에 대해 알리는 데 사용됩니다. Attach 메서드는 엔터티를 Unchanged 상태로 표시합니다.

연결이 끊어진 엔터티가 DbContext로 연결된 다음 C # 코드를 살펴 보겠습니다.

class Program {

   static void Main(string[] args) {

      var student = new Student {

         ID = 1001,
         FirstMidName = "Wasim",
         LastName = "Akram",
         EnrollmentDate = DateTime.Parse("2015-10-10"), 

         Enrollments = new List<Enrollment> {
            new Enrollment { EnrollmentID = 2001, CourseID = 4022, StudentID = 1001 },
            new Enrollment { EnrollmentID = 2002, CourseID = 4025, StudentID = 1001 },
         }
			
      };

      using (var context = new UniContextEntities()) {

         context.Students.Attach(student);
         Console.WriteLine("New Student ({0} {1}): {2}", 
            student.FirstMidName, student.LastName, context.Entry(student).State);

         foreach (var enrollment in student.Enrollments) {
            Console.WriteLine("Enrollment ID: {0} State: {1}", enrollment.EnrollmentID, 
               context.Entry(enrollment).State);
         }

         Console.WriteLine("Press any key to exit...");
         Console.ReadKey();
      }
   }
}

Attach () 메서드로 위의 코드를 실행하면 다음과 같은 출력을 받게됩니다.

New Student   (Wasim  Akram): Unchanged
Enrollment ID: 2001 State: Unchanged
Enrollment ID: 2002 State: Unchanged
Press any key to exit...

이 장에서는 Entity Framework Designer를 사용하여 TVF (테이블 반환 함수)를 매핑하는 방법과 LINQ 쿼리에서 TVF를 호출하는 방법을 알아 봅니다.

  • TVF는 현재 Database First 워크 플로에서만 지원됩니다.

  • Entity Framework 버전 5에서 처음 도입되었습니다.

  • TVF를 사용하려면 .NET Framework 4.5 이상을 대상으로해야합니다.

  • 저장 프로 시저와 매우 유사하지만 한 가지 중요한 차이점이 있습니다. 즉, TVF의 결과를 구성 할 수 있습니다. 즉, TVF의 결과는 LINQ 쿼리에서 사용할 수 있지만 저장 프로 시저의 결과는 사용할 수 없습니다.

File → New → Project에서 새 프로젝트를 생성하는 다음 예제를 살펴 보겠습니다.

Step 1 − 중간 창에서 콘솔 애플리케이션을 선택하고 이름 필드에 TableValuedFunctionDemo를 입력합니다.

Step 2 − 서버 탐색기에서 데이터베이스를 마우스 오른쪽 버튼으로 클릭합니다.

Step 3 − 새 쿼리를 선택하고 T-SQL 편집기에 다음 코드를 입력하여 데이터베이스에 새 테이블을 추가합니다.

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id =
   OBJECT_ID(N'[dbo].[StudentGrade]') AND type in (N'U'))

BEGIN

   CREATE TABLE [dbo].[StudentGrade](

      [EnrollmentID] [int] IDENTITY(1,1) NOT NULL,
      [CourseID] [int] NOT NULL,
      [StudentID] [int] NOT NULL,
      [Grade] [decimal](3, 2) NULL,

      CONSTRAINT [PK_StudentGrade] PRIMARY KEY CLUSTERED ([EnrollmentID] ASC)

      WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]

   ) ON [PRIMARY]

END
GO

Step 4 − 편집기를 마우스 오른쪽 버튼으로 클릭하고 실행을 선택합니다.

Step 5− 데이터베이스를 마우스 오른쪽 버튼으로 클릭하고 새로 고침을 클릭합니다. 데이터베이스에 새로 추가 된 테이블이 표시됩니다.

Step 6− 이제 코스에 대한 학생 성적을 반환하는 함수를 만듭니다. T-SQL 편집기에 다음 코드를 입력합니다.

CREATE FUNCTION [dbo].[GetStudentGradesForCourse]

(@CourseID INT)

RETURNS TABLE

RETURN
   SELECT [EnrollmentID],
      [CourseID],
      [StudentID],
      [Grade]
   FROM   [dbo].[StudentGrade]
   WHERE  CourseID = @CourseID

Step 7 − 편집기를 마우스 오른쪽 버튼으로 클릭하고 실행을 선택합니다.

이제 함수가 생성 된 것을 볼 수 있습니다.

Step 8 − 솔루션 탐색기에서 프로젝트 이름을 마우스 오른쪽 버튼으로 클릭하고 추가 → 새 항목을 선택합니다.

Step 9 − 그런 다음 템플릿 창에서 ADO.NET 엔티티 데이터 모델을 선택합니다.

Step 10 − 이름으로 TVFModel을 입력하고 추가를 클릭합니다.

Step 11 − 모델 콘텐츠 선택 대화 상자에서 데이터베이스에서 EF 디자이너를 선택하고 다음을 클릭합니다.

Step 12 − 데이터베이스를 선택하고 다음을 클릭합니다.

Step 13 − 데이터베이스 개체 선택 대화 상자에서 테이블,보기를 선택합니다.

Step 14 − Stored Procedures and Functions 노드 아래에있는 GetStudentGradesForCourse 함수를 선택하고 Finish를 클릭합니다.

Step 15 −보기 → 다른 창 → 엔티티 데이터 모델 브라우저를 선택하고 함수 가져 오기에서 GetStudentGradesForCourse를 마우스 오른쪽 버튼으로 클릭하고 편집을 선택합니다.

다음 대화 상자가 표시됩니다.

Step 16 − Entities 라디오 버튼을 클릭하고이 함수의 반환 유형으로 콤보 박스에서 Enrollment를 선택하고 Ok를 클릭합니다.

데이터베이스에서 Course ID = 4022에 등록 된 모든 학생의 성적이 검색되는 다음 C # 코드를 살펴 보겠습니다.

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         var CourseID = 4022;

         // Return all the best students in the Microeconomics class.
         var students = context.GetStudentGradesForCourse(CourseID);

         foreach (var result in students) {
            Console.WriteLine("Student ID:  {0}, Grade: {1}",
               result.StudentID, result.Grade);
         }

         Console.ReadKey();
      }
   }
}

위의 코드가 컴파일되고 실행되면 다음과 같은 출력을 받게됩니다.

Student ID: 1, Grade: 2
Student ID: 4, Grade: 4
Student ID: 9, Grade: 3.5

더 나은 이해를 위해 위의 예를 단계별로 실행하는 것이 좋습니다.

Entity Framework에서 LINQ를 사용하여 엔터티 클래스로 쿼리 할 수 ​​있습니다. DbCOntext를 사용하여 데이터베이스에 대해 원시 SQL을 사용하여 쿼리를 직접 실행할 수도 있습니다. 이 기술은 Code First 및 EF Designer로 만든 모델에 동일하게 적용 할 수 있습니다.

기존 엔터티에 대한 SQL 쿼리

DbSet의 SqlQuery 메서드를 사용하면 엔터티 인스턴스를 반환하는 원시 SQL 쿼리를 작성할 수 있습니다. 반환 된 개체는 LINQ 쿼리에서 반환 된 것처럼 컨텍스트에 의해 추적됩니다. 예를 들면-

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         var students = context.Students.SqlQuery("SELECT * FROM dbo.Student").ToList();

         foreach (var student in students) {
            string name = student.FirstMidName + " " + student.LastName;
            Console.WriteLine("ID: {0}, Name: {1}, \tEnrollment Date {2} ",
               student.ID, name, student.EnrollmentDate.ToString());
         }

         Console.ReadKey();
      }
   }
}

위의 코드는 데이터베이스에서 모든 학생을 검색합니다.

비 엔터티 유형에 대한 SQL 쿼리

기본 형식을 포함하여 모든 형식의 인스턴스를 반환하는 SQL 쿼리는 Database 클래스의 SqlQuery 메서드를 사용하여 만들 수 있습니다. 예를 들면-

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         var studentNames = context.Database.SqlQuery
            <string>("SELECT FirstMidName FROM dbo.Student").ToList();

         foreach (var student in studentNames) {
            Console.WriteLine("Name: {0}", student);
         }

         Console.ReadKey();
      }
   }
}

데이터베이스에 대한 SQL 명령

ExecuteSqlCommnad 메서드는 삽입, 업데이트 또는 삭제 명령과 같은 쿼리가 아닌 명령을 데이터베이스에 보내는 데 사용됩니다. 학생의 이름이 ID = 1로 업데이트되는 다음 코드를 살펴 보겠습니다.

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         //Update command

         int noOfRowUpdated = context.Database.ExecuteSqlCommand("Update 
            student set FirstMidName = 'Ali' where ID = 1");

         context.SaveChanges();

         var student = context.Students.SqlQuery("SELECT * FROM
            dbo.Student where ID = 1").Single();

         string name = student.FirstMidName + " " + student.LastName;

         Console.WriteLine("ID: {0}, Name: {1}, \tEnrollment Date {2} ", 
            student.ID, name, student.EnrollmentDate.ToString());

         Console.ReadKey();
      }
   }
}

위의 코드는 데이터베이스에서 모든 학생의 이름을 검색합니다.

Entity Framework에서이 기능을 사용하면 열거 형 유형 인 도메인 클래스에 속성을 정의하고이를 정수 유형의 데이터베이스 열에 매핑 할 수 있습니다. 그런 다음 Entity Framework는 데이터를 쿼리하고 저장할 때 관련 열거 형간에 데이터베이스 값을 변환합니다.

  • 열거 형 유형은 응답 수가 고정 된 속성으로 작업 할 때 모든 종류의 이점이 있습니다.

  • 열거 형을 사용하면 응용 프로그램의 보안과 안정성이 모두 향상됩니다.

  • 열거 형은 사용자가 실수를하기를 훨씬 더 어렵게 만들고 주입 공격과 같은 문제가 존재하지 않습니다.

  • Entity Framework에서 열거 형은 다음과 같은 기본 유형을 가질 수 있습니다.

    • Byte
    • Int16
    • Int32
    • Int64
    • SByte
  • 열거 형 요소의 기본 기본 유형은 int입니다.

  • 기본적으로 첫 번째 열거 자의 값은 0이고 연속 된 각 열거 자의 값은 1 씩 증가합니다.

디자이너에서 엔터티를 만들고 몇 가지 속성을 추가하는 다음 예제를 살펴 보겠습니다.

Step 1 − 파일 → 새로 만들기 → 프로젝트 메뉴 옵션에서 새 프로젝트를 만듭니다.

Step 2 − 왼쪽 창에서 콘솔 애플리케이션을 선택합니다.

Step 3 − 프로젝트 이름으로 EFEnumDemo를 입력하고 확인을 클릭합니다.

Step 4 − 솔루션 탐색기에서 프로젝트 이름을 마우스 오른쪽 버튼으로 클릭하고 추가 → 새 항목 메뉴 옵션을 선택합니다.

Step 5 − 템플릿 창에서 ADO.NET 엔티티 데이터 모델을 선택합니다.

Step 6 − 파일 이름으로 EFEnumModel.edmx를 입력하고 추가를 클릭합니다.

Step 7 − 엔티티 데이터 모델 마법사 페이지에서 빈 EF 디자이너 모델을 선택합니다.

Step 8 − 마침 클릭

Step 9 − 그런 다음 디자이너 창을 마우스 오른쪽 버튼으로 클릭하고 추가 → 엔티티를 선택합니다.

다음 이미지와 같이 새 엔터티 대화 상자가 나타납니다.

Step 10 − 엔티티 이름으로 부서를 입력하고 속성 이름으로 DeptID를 입력하고 속성 유형을 Int32로두고 확인을 클릭합니다.

Step 11 − 엔티티를 마우스 오른쪽 버튼으로 클릭하고 새로 추가 → 스칼라 속성을 선택합니다.

Step 12 − 새 속성의 이름을 DeptName으로 변경합니다.

Step 13 − 새 속성의 유형을 Int32로 변경합니다 (기본적으로 새 속성은 문자열 유형입니다).

Step 14 − 유형을 변경하려면 속성 창을 열고 유형 속성을 Int32로 변경합니다.

Step 15 − Entity Framework Designer에서 Name 속성을 마우스 오른쪽 버튼으로 클릭하고 Convert to enum을 선택합니다.

Step 16 − Add Enum Type 대화 상자에서 Enum Type Name에 DepartmentNames를 입력하고 Underlying Type을 Int32로 변경 한 후 Physics, Chemistry, Computer, Economics와 같은 멤버를 유형에 추가합니다.

Step 17 − 확인을 클릭합니다.

모델 브라우저 창으로 전환하면 유형이 Enum 유형 노드에도 추가 된 것을 볼 수 있습니다.

Model First 접근 방식 장에서 언급 한 모든 단계에 따라 모델에서 데이터베이스를 생성 해 보겠습니다.

Step 1 − Entity Designer 화면을 마우스 오른쪽 버튼으로 클릭하고 모델에서 데이터베이스 생성을 선택합니다.

데이터베이스 생성 마법사의 데이터 연결 선택 대화 상자가 표시됩니다.

Step 2 − 새 연결 버튼을 클릭합니다.

Step 3 − 데이터베이스의 서버 이름과 EnumDemo를 입력하고 확인을 클릭합니다.

Step 4 − 새 데이터베이스를 생성 할 것인지 묻는 대화 상자가 나타나면 예를 클릭합니다.

Step 5− 다음을 클릭하면 데이터베이스 생성 마법사가 데이터베이스 생성을위한 데이터 정의 언어 (DDL)를 생성합니다. 이제 마침을 클릭하십시오.

Step 6 − T-SQL 편집기를 마우스 오른쪽 버튼으로 클릭하고 실행을 선택합니다.

Step 7 − 생성 된 스키마를 보려면 SQL Server 개체 탐색기에서 데이터베이스 이름을 마우스 오른쪽 버튼으로 클릭하고 새로 고침을 선택합니다.

데이터베이스에 Departments 테이블이 표시됩니다.

컨텍스트에 대한 몇 가지 새로운 부서 개체가 추가되고 저장되는 다음 예제를 살펴 보겠습니다. 그런 다음 컴퓨터 부서를 검색하십시오.

class Program {

   static void Main(string[] args) {

      using (var context = new EFEnumModelContainer()) {

         context.Departments.Add(new Department { DeptName = DepartmentNames.Physics});
         context.Departments.Add(new Department { DeptName = DepartmentNames.Computer});
         context.Departments.Add(new Department { DeptName = DepartmentNames.Chemistry});
         context.Departments.Add(new Department { DeptName = DepartmentNames.Economics});

         context.SaveChanges();

         var department = (
            from d in context.Departments
            where d.DeptName == DepartmentNames.Computer
            select d
         ).FirstOrDefault();

         Console.WriteLine(
            "Department ID: {0}, Department Name: {1}", 
               department.DeptID, department.DeptName
         );

         Console.ReadKey();
      }
   }
}

위의 코드가 실행되면 다음과 같은 출력을 받게됩니다.

Department ID: 2, Department Name: Computer

더 나은 이해를 위해 위의 예를 단계별로 실행하는 것이 좋습니다.

Asynchronous programming메인 스레드가 자체 작업을 계속할 수 있도록 백그라운드에서 작업을 실행하는 작업이 포함됩니다. 이런 식으로 메인 스레드는 백그라운드 스레드가 작업을 처리하는 동안 사용자 인터페이스의 응답 성을 유지할 수 있습니다.

  • Entity Framework 6.0은 데이터 쿼리 및 저장을위한 비동기 작업을 지원합니다.

  • 비동기 작업은 다음과 같은 방식으로 애플리케이션을 도울 수 있습니다.

    • 응용 프로그램이 사용자 상호 작용에 더 반응하도록 만듭니다.
    • 응용 프로그램의 전반적인 성능 향상
  • 다양한 방법으로 비동기 작업을 실행할 수 있습니다. 그러나 async / await 키워드가 .NET Framework 4.5에 도입되어 작업이 간단 해졌습니다.

  • 따라야 할 유일한 것은 다음 코드 조각에서 설명하는 async / await 패턴입니다.

DatabaseOperations 메서드가 새 학생을 데이터베이스에 저장 한 다음 데이터베이스에서 모든 학생을 검색하고 마지막에 콘솔에 추가 메시지가 인쇄되는 다음 예제 (async / await를 사용하지 않음)를 살펴 보겠습니다.

class Program {

   static void Main(string[] args) {
      Console.WriteLine("Database Operations Started");
      DatabaseOperations();
		
      Console.WriteLine();
      Console.WriteLine("Database Operations Completed");
      Console.WriteLine();
      Console.WriteLine("Entity Framework Tutorials");
      Console.ReadKey();
   }

   public static void DatabaseOperations() {

      using (var context = new UniContextEntities()) {

         // Create a new student and save it

         context.Students.Add(new Student {
            FirstMidName = "Akram", 
            LastName = "Khan", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())});

         Console.WriteLine("Calling SaveChanges.");
         context.SaveChanges();
         Console.WriteLine("SaveChanges completed.");

         // Query for all Students ordered by first name

         var students = (from s in context.Students
            orderby s.FirstMidName select s).ToList();

         // Write all students out to Console

         Console.WriteLine();
         Console.WriteLine("All Student:");

         foreach (var student in students) {
            string name = student.FirstMidName + " " + student.LastName;
            Console.WriteLine(" " + name);
         }
      }
   }
}

위의 코드가 실행되면 다음과 같은 출력을 받게됩니다.

Calling SaveChanges.
SaveChanges completed.
All Student:
Akram Khan
Ali Khan
Ali Alexander
Arturo Anand
Bill Gates
Gytis Barzdukas
Laura  Nornan
Meredith fllonso
Nino Olioetto
Peggy Justice
Yan Li

Entity Framework Tutorials

새로운 async 및 await 키워드를 사용하고 Program.cs를 다음과 같이 변경해 보겠습니다.

  • EF 비동기 확장 메서드를 제공 할 System.Data.Entity 네임 스페이스를 추가합니다.

  • Task 유형을 사용할 수 있도록 System.Threading.Tasks 네임 스페이스를 추가합니다.

  • 최신 정보 DatabaseOperations 표시 될 async 그리고 반환 Task.

  • SaveChanges의 비동기 버전을 호출하고 완료를 기다립니다.

  • ToList의 비동기 버전을 호출하고 결과를 기다립니다.

class Program {

   static void Main(string[] args) {
      var task = DatabaseOperations();
      Console.WriteLine();
      Console.WriteLine("Entity Framework Tutorials");
      task.Wait();
      Console.ReadKey();
   }

   public static async Task DatabaseOperations() {

      using (var context = new UniContextEntities()) {

         // Create a new blog and save it

         context.Students.Add(new Student {
            FirstMidName = "Salman", 
            LastName = "Khan", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())});

         Console.WriteLine("Calling SaveChanges.");
         await context.SaveChangesAsync();
         Console.WriteLine("SaveChanges completed.");

         // Query for all Students ordered by first name

         var students = await (from s in context.Students 
            orderby s.FirstMidName select s).ToListAsync();

         // Write all students out to Console

         Console.WriteLine();
         Console.WriteLine("All Student:");

         foreach (var student in students) {
            string name = student.FirstMidName + " " + student.LastName; 
            Console.WriteLine(" " + name);
         }
      }
   }
}

실행시 다음 출력이 생성됩니다.

Calling SaveChanges.
Entity Framework Tutorials
SaveChanges completed.
All Student:
Akram Khan
Ali Khan
Ali Alexander
Arturo Anand
Bill Gates
Gytis Barzdukas
Laura  Nornan
Meredith fllonso
Nino Olioetto
Peggy Justice
Salman Khan
Yan Li

이제 코드가 비동기식이므로 프로그램의 다른 실행 흐름을 관찰 할 수 있습니다.

  • SaveChanges는 새 Student를 데이터베이스로 푸시하기 시작하고 DatabaseOperations 메서드가 반환되고 (실행이 완료되지 않았더라도) Main 메서드의 프로그램 흐름이 계속됩니다.

  • 그런 다음 메시지가 콘솔에 기록됩니다.

  • 관리 스레드는 데이터베이스 작업이 완료 될 때까지 Wait 호출에서 차단됩니다. 완료되면 나머지 DatabaseOperations가 실행됩니다.

  • SaveChanges가 완료됩니다.

  • 데이터베이스에서 모든 학생을 검색하고 콘솔에 기록합니다.

더 나은 이해를 위해 위의 예를 단계별로 실행하는 것이 좋습니다.

이제 Entity Framework를 사용하면 애플리케이션의 모든 부분이 Entity Framework를 인식하지 않고도 Entity Framework의 이점을 누릴 수 있으며, 엔터티를 인프라에서 분리 할 수 ​​있습니다. 지속되는 방식 (데이터가 저장되는 위치 및 개체간에 데이터가 왕복하는 방식)에 관계없이 비즈니스 규칙에 집중할 수있는 클래스를 만들 수 있습니다.

영구 무지 엔티티 생성

앞의 단락에서는 소비하는 데이터의 소스에 대한 자세한 정보가없는 방법을 설명했습니다. 이것은 지속성 무지의 본질을 강조하는데, 이는 클래스와 그 주변의 많은 애플리케이션 계층이 데이터가 저장되는 방식에 관심이없는 경우입니다.

  • .NET 3.5 버전의 Entity Framework에서 기존 클래스를 사용하려면 EntityObject에서 파생되도록 강제로 수정해야했습니다.

  • .NET 4에서는 더 이상 필요하지 않습니다. Entity Framework 작업에 참여하기 위해 엔터티를 수정할 필요가 없습니다.

  • 이를 통해 느슨한 결합 및 우려 분리를 수용하는 애플리케이션을 구축 할 수 있습니다.

  • 이러한 코딩 패턴을 사용하면 클래스가 자신의 작업에만 관심이 있고 UI를 포함한 애플리케이션의 많은 계층이 Entity Framework API와 같은 외부 논리에 종속되지 않지만 이러한 외부 API는 우리와 상호 작용할 수 있습니다. 엔티티.

Entity Framework를 사용하여 엔터티를 유지할 때 두 가지 방법 (연결 및 연결 해제)이 있습니다. 두 가지 방법 모두 자체적으로 중요합니다. 연결된 시나리오의 경우 변경 내용은 컨텍스트에 의해 추적되지만 연결이 끊어진 시나리오의 경우 엔터티 상태에 대한 컨텍스트를 알려야합니다.

연결된 시나리오

연결된 시나리오는 엔티티가 데이터베이스에서 검색되고 동일한 컨텍스트에서 수정되는 경우입니다. 연결된 시나리오의 경우 Windows 서비스가 있고 해당 엔터티로 일부 비즈니스 작업을 수행한다고 가정하여 컨텍스트를 열고 모든 엔터티를 반복하고 비즈니스 작업을 수행 한 다음 변경 사항을 동일한 컨텍스트로 저장합니다. 처음에 열었습니다.

데이터베이스에서 학생을 검색하고 학생의 이름을 업데이트 한 다음 변경 사항을 데이터베이스에 저장하는 다음 예제를 살펴 보겠습니다.

class Program {

   static void Main(string[] args) {

      using (var context = new MyContext()) {

         var studentList = context.Students.ToList();

         foreach (var stdnt in studentList) {
            stdnt.FirstMidName = "Edited " + stdnt.FirstMidName;
         }

         context.SaveChanges();

         //// Display all Students from the database

         var students = (from s in context.Students
            orderby s.FirstMidName select s).ToList<Student>();

         Console.WriteLine("Retrieve all Students from the database:");

         foreach (var stdnt in students) {
            string name = stdnt.FirstMidName + " " + stdnt.LastName;
            Console.WriteLine("ID: {0}, Name: {1}", stdnt.ID, name);
         }

         Console.ReadKey();
      }
   }
}

위의 코드가 컴파일되고 실행되면 다음 출력이 표시되고 다음 출력과 같이 이름 앞에 편집 된 단어가 첨부 된 것을 볼 수 있습니다.

Retrieve all Students from the database: 
ID: 1, Name: Edited Edited Alain Bomer 
ID: 2, Name: Edited Edited Mark Upston

연결이 끊긴 시나리오

연결이 끊긴 시나리오는 엔티티가 데이터베이스에서 검색되고 다른 컨텍스트에서 수정되는 경우입니다. 프레젠테이션 레이어에 일부 데이터를 표시하고 n 계층 응용 프로그램을 사용하고 있으므로 컨텍스트를 열고 데이터를 가져온 다음 마지막으로 컨텍스트를 닫는 것이 좋습니다. 여기에서 데이터를 가져오고 컨텍스트를 닫았으므로 가져온 엔티티는 더 이상 추적되지 않으며 연결이 끊긴 시나리오입니다.

Add 메서드를 사용하여 연결이 끊긴 새로운 Student 엔터티가 컨텍스트에 추가되는 다음 코드를 살펴 보겠습니다.

class Program {

   static void Main(string[] args) {

      var student = new Student {
         ID = 1001, 
         FirstMidName = "Wasim", 
         LastName = "Akram", 
         EnrollmentDate = DateTime.Parse( DateTime.Today.ToString())
      };

      using (var context = new MyContext()) {

         context.Students.Add(student);
         context.SaveChanges();

         //// Display all Students from the database

         var students = (from s in context.Students 
            orderby s.FirstMidName select s).ToList<Student>();

         Console.WriteLine("Retrieve all Students from the database:");

         foreach (var stdnt in students) {
            string name = stdnt.FirstMidName + " " + stdnt.LastName;
            Console.WriteLine("ID: {0}, Name: {1}", stdnt.ID, name);
         }

         Console.ReadKey();
      }
   }
}

위의 코드가 컴파일되고 실행되면 다음과 같은 출력이 표시됩니다.

Retrieve all Students from the database:
ID: 1, Name: Edited Edited Edited Alain Bomer
ID: 2, Name: Edited Edited Edited Mark Upston
ID: 3, Name: Wasim Akram

LINQ to 엔터티

LINQ to Entities를 이해하는 데 가장 중요한 개념 중 하나는 선언적 언어라는 것입니다. 정보를 얻는 방법보다는 필요한 정보를 정의하는 데 중점을 둡니다.

  • 즉, 데이터 작업에 더 많은 시간을 할애하고 데이터베이스 액세스와 같은 작업을 수행하는 데 필요한 기본 코드를 파악하는 데 드는 시간을 줄일 수 있습니다.

  • 선언적 언어가 실제로 개발자의 제어를 제거하지는 않지만 개발자가 중요한 것에주의를 집중하는 데 도움이된다는 것을 이해하는 것이 중요합니다.

LINQ to Entities 필수 키워드

LINQ 쿼리를 만드는 데 사용되는 기본 키워드를 아는 것이 중요합니다. 기억해야 할 키워드는 몇 개 뿐이지 만 다양한 방법으로 조합하여 특정 결과를 얻을 수 있습니다. 다음 목록은 이러한 기본 키워드를 포함하고 각 키워드에 대한 간단한 설명을 제공합니다.

Sr. No. 키워드 및 설명
1

Ascending

정렬 작업이 범위의 최소 (또는 최저) 요소에서 범위의 가장 높은 요소까지 발생하도록 지정합니다. 이것은 일반적으로 기본 설정입니다. 예를 들어, 알파벳 정렬을 수행 할 때 정렬은 A에서 Z까지의 범위입니다.

2

By

그룹화를 구현하는 데 사용되는 필드 또는 표현식을 지정합니다. 필드 또는 식은 그룹화 작업을 수행하는 데 사용되는 키를 정의합니다.

Descending

정렬 작업이 범위의 가장 큰 (또는 가장 높은) 요소에서 범위의 가장 낮은 요소까지 발생하도록 지정합니다. 예를 들어, 알파벳 정렬을 수행 할 때 정렬은 Z에서 A까지의 범위입니다.

4

Equals

조인 문의 왼쪽 및 오른쪽 절 사이에서 기본 컨텍스트 데이터 소스를 보조 컨텍스트 데이터 소스에 조인하는 데 사용됩니다. equals 키워드의 왼쪽에있는 필드 또는 표현식은 기본 데이터 소스를 지정하고 equals 키워드의 오른쪽에있는 필드 또는 표현식은 보조 데이터 소스를 지정합니다.

5

From

필요한 정보를 얻는 데 사용되는 데이터 소스를 지정하고 범위 변수를 정의합니다. 이 변수는 루프에서 반복에 사용되는 변수와 동일한 목적을 갖습니다.

6

Group

지정한 키 값을 사용하여 출력을 그룹으로 구성합니다. 여러 그룹 절을 사용하여 여러 수준의 출력 구성을 만듭니다. 그룹 절의 순서는 그룹화 순서에서 특정 키 값이 나타나는 깊이를 결정합니다. 이 키워드를 by와 결합하여 특정 컨텍스트를 만듭니다.

7

In

여러 가지 방법으로 사용됩니다. 이 경우 키워드는 쿼리에 사용되는 컨텍스트 데이터베이스 소스를 결정합니다. 조인으로 작업 할 때 조인에 사용되는 각 컨텍스트 데이터베이스 소스에 in 키워드가 사용됩니다.

8

Into

조인, 그룹 및 선택과 같은 LINQ 쿼리 절에 대한 참조로 사용할 수있는 식별자를 지정합니다.

9

Join

마스터 / 세부 사항 설정과 같이 두 개의 관련 데이터 원본에서 단일 데이터 원본을 만듭니다. 조인은 내부 조인을 기본값으로 사용하여 내부, 그룹 또는 왼쪽-외부 조인을 지정할 수 있습니다. msdn.microsoft.com 에서 조인에 대해 자세히 알아볼 수 있습니다.

10

Let

쿼리 식에 하위 식 결과를 저장하는 데 사용할 수있는 범위 변수를 정의합니다. 일반적으로 범위 변수는 추가 열거 출력을 제공하거나 쿼리의 효율성을 높이는 데 사용됩니다 (문자열의 소문자 값 찾기와 같은 특정 작업을 두 번 이상 수행 할 필요가 없도록).

11

On

조인을 구현하는 데 사용되는 필드 또는 식을 지정합니다. 필드 또는 표현식은 두 컨텍스트 데이터 소스에 공통적 인 요소를 정의합니다.

12

Orderby

질의에 대한 정렬 순서를 만듭니다. 오름차순 또는 내림차순 키워드를 추가하여 정렬 순서를 제어 할 수 있습니다. 여러 orderby 절을 사용하여 여러 수준의 정렬을 만듭니다. orderby 절의 순서는 정렬식이 처리되는 순서를 결정하므로 다른 순서를 사용하면 출력이 달라집니다.

13

Where

LINQ가 데이터 소스에서 검색해야하는 항목을 정의합니다. 하나 이상의 부울 식을 사용하여 검색 할 항목의 세부 사항을 정의합니다. 부울 표현식은 && (AND) 및 ||를 사용하여 서로 분리됩니다. (OR) 연산자.

14

Select

반환 할 정보를 지정하여 LINQ 쿼리의 출력을 결정합니다. 이 문은 반복 프로세스 중에 LINQ가 반환하는 요소의 데이터 형식을 정의합니다.

투사

프로젝션 쿼리는 데이터베이스에서 특정 필드 만 검색하여 애플리케이션의 효율성을 향상시킵니다.

  • 데이터가 있으면 출력하기 전에 데이터를 형성하기 위해 필요에 따라이를 프로젝션하거나 필터링 할 수 있습니다.

  • 모든 LINQ to Entities 식의 주요 작업은 데이터를 가져와 출력으로 제공하는 것입니다.

이 장의 "LINQ to Entities 쿼리 개발"섹션에서는이 기본 작업을 수행하는 기술을 보여줍니다.

학생 목록을 검색 할 다음 코드를 살펴 보겠습니다.

using (var context = new UniContextEntities()) {

   var studentList = from s in context.Students select s;

   foreach (var student in studentList) {
      string name = student.FirstMidName + " " + student.LastName;
      Console.WriteLine("ID : {0}, Name: {1}", student.ID, name);
   }
}

단일 개체

단일 학생 객체를 검색하려면 시퀀스의 첫 번째 요소를 반환하는 First () 또는 FirstOrDefault 열거 가능한 메서드를 사용할 수 있습니다. First와 FirstOrDefault의 차이점은 제공된 기준에 대한 결과 데이터가 없으면 First ()가 예외를 던지고 결과 데이터가 없으면 FirstOrDefault ()가 기본값 null을 반환한다는 것입니다. 아래 코드 스 니펫에서 목록의 첫 번째 학생은 이름이 Ali 인 학생을 검색합니다.

using (var context = new UniContextEntities()) {

   var student = (from s in context.Students where s.FirstMidName 
      == "Ali" select s).FirstOrDefault<Student>();

   string name = student.FirstMidName + " " + student.LastName;
   Console.WriteLine("ID : {0}, Name: {1}", student.ID, name);
}

Single () 또는 SingleOrDefault를 사용하여 시퀀스의 특정 단일 요소를 반환하는 단일 학생 객체를 가져올 수도 있습니다. 다음 예에서는 ID가 2 인 단일 학생이 검색됩니다.

using (var context = new UniContextEntities()) {

   var student = (from s in context.Students where s.ID 
      == 2 select s).SingleOrDefault<Student>();
   string name = student.FirstMidName + " " + student.LastName;
	
   Console.WriteLine("ID : {0}, Name: {1}", student.ID, name);
   Console.ReadKey();
}

개체 목록

이름이 Ali 인 학생 목록을 검색하려면 ToList () 열거 가능한 메서드를 사용할 수 있습니다.

using (var context = new UniContextEntities()) {

   var studentList = (from s in context.Students where s.FirstMidName 
      == "Ali" select s).ToList();

   foreach (var student in studentList) {
      string name = student.FirstMidName + " " + student.LastName;
      Console.WriteLine("ID : {0}, Name: {1}", student.ID, name);
   }

   Console.ReadKey();
}

주문

특정 순서로 데이터 / 목록을 검색하려면 orderby 키워드를 사용할 수 있습니다. 다음 코드에서 학생의 스 니펫 목록은 오름차순으로 검색됩니다.

using (var context = new UniContextEntities()) {

   var studentList = (from s in context.Students orderby
      s.FirstMidName ascending select s).ToList();

   foreach (var student in studentList) {
      string name = student.FirstMidName + " " + student.LastName;
      Console.WriteLine("ID : {0}, Name: {1}", student.ID, name);
   }

   Console.ReadKey();
}

표준 대 프로젝션 Entity Framework 쿼리

ID, FirstMidName, LastName 및 EnrollmentDate가 포함 된 Student 모델이 있다고 가정 해 보겠습니다. 학생 목록을 반환하려면 표준 쿼리가 모든 필드를 반환합니다. 그러나 ID, FirstMidName 및 LastName 필드가 포함 된 학생 목록 만 얻으려는 경우. 프로젝션 쿼리를 사용해야하는 곳입니다. 다음은 프로젝션 쿼리의 간단한 예입니다.

using (var context = new UniContextEntities()) {

   var studentList = from s in context.Students
      orderby s.FirstMidName ascending
      where s.FirstMidName == "Ali"

   select new {s.ID, s.FirstMidName, s.LastName};

   foreach (var student in studentList) {
      string name = student.FirstMidName + " " + student.LastName;
      Console.WriteLine("ID : {0}, Name: {1}", student.ID, name);
   }

   Console.ReadKey();
}

위의 프로젝션 쿼리는 EnrollmentDate 필드를 제외합니다. 이렇게하면 응용 프로그램이 훨씬 빨라집니다.

Entity Framework 6.0에는 다음과 같은 새로운 기능이 도입되었습니다. Logging SQL. Entity Framework로 작업하는 동안 명령 또는 이에 상응하는 SQL 쿼리를 데이터베이스에 전송하여 CRUD (만들기, 읽기, 업데이트 및 삭제) 작업을 수행합니다.

  • Entity Framework의이 기능은 Entity Framework에서 내부적으로 생성 된 동등한 SQL 쿼리를 캡처하여 출력으로 제공하는 것입니다.

  • Entity Framework 6 이전에는 데이터베이스 쿼리 및 명령을 추적해야 할 때마다 개발자가 타사 추적 유틸리티 또는 데이터베이스 추적 도구를 사용할 수밖에 없었습니다.

  • Entity Framework 6에서이 새로운 기능은 Entity Framework에서 수행하는 모든 작업을 로깅하는 간단한 방법을 제공합니다.

  • Entity Framework에서 수행되는 모든 활동은 DbContext.Database.Log를 사용하여 기록됩니다.

새 학생이 데이터베이스에 추가되는 다음 코드를 살펴 보겠습니다.

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         context.Database.Log = Console.Write;

         // Create a new student and save it

         context.Students.Add(new Student {
            FirstMidName = "Salman", 
            LastName = "Khan", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
         });

         context.SaveChanges();
         Console.ReadKey();
      }
   }
}

위 코드가 실행되면 실제로 위 코드에서 EF가 수행 한 모든 활동의 로그인 다음 출력이 표시됩니다.

Opened connection at 10/28/2015 6:27:35 PM +05:00
Started transaction at 10/28/2015 6:27:35 PM +05:00
INSERT [dbo].[Student]([LastName], [FirstMidName], [EnrollmentDate])
VALUES (@0, @1, @2)
SELECT [ID]
FROM [dbo].[Student]
WHERE @@ROWCOUNT > 0 AND [ID] = scope_identity()
-- @0: 'Khan' (Type = String, Size = -1)
-- @1: 'Salman' (Type = String, Size = -1)
-- @2: '10/28/2015 12:00:00 AM' (Type = DateTime)
-- Executing at 10/28/2015 6:27:35 PM +05:00
-- Completed in 5 ms with result: SqlDataReader
Committed transaction at 10/28/2015 6:27:35 PM +05:00
Closed connection at 10/28/2015 6:27:35 PM +05:00

Log 속성이 설정되면 다음 활동이 기록됩니다.

  • SaveChanges의 일부로 생성 된 삽입, 업데이트 및 삭제를 포함한 쿼리와 같은 모든 다른 종류의 명령에 대한 SQL

  • Parameters

  • 명령이 비동기 적으로 실행되고 있는지 여부

  • 명령 실행이 시작된시기를 나타내는 타임 스탬프

  • 명령이 성공적으로 완료되었거나 실패했습니다.

  • 결과 값의 일부 표시

  • 명령을 실행하는 데 걸린 대략적인 시간

다른 장소에 로그인

이미 로깅 프레임 워크가 있고 로깅 방법을 정의한 경우 다른 위치에 로깅 할 수도 있습니다.

다른 클래스 MyLogger가있는 다음 예제를 살펴 보겠습니다.

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         context.Database.Log = s ⇒ MyLogger.Log("EFLoggingDemo", s);

         // Create a new student and save it

         context.Students.Add(new Student {
            FirstMidName = "Salman", 
            LastName = "Khan", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
         });

         context.SaveChanges();
         Console.ReadKey();
      }
   }
}

public class MyLogger {

   public static void Log(string application, string message) {
      Console.WriteLine("Application: {0}, EF Message: {1} ",application, message);
   }
}

더 나은 이해를 위해 위의 예를 단계별로 실행하는 것이 좋습니다.

Entity Framework 6.0에는 다음과 같은 또 다른 새로운 기능이 있습니다. Interceptor또는 차단. 차단 코드는interception interfaces. 예를 들어 IDbCommandInterceptor 인터페이스는 EF가 ExecuteNonQuery, ExecuteScalar, ExecuteReader 및 관련 메서드를 호출하기 전에 호출되는 메서드를 정의합니다.

  • Entity Framework는 차단을 사용하여 진정으로 빛날 수 있습니다. 이 접근 방식을 사용하면 코드를 정리할 필요없이 일시적으로 더 많은 정보를 캡처 할 수 있습니다.

  • 이를 구현하려면 사용자 지정 인터셉터를 만들고 그에 따라 등록해야합니다.

  • IDbCommandInterceptor 인터페이스를 구현하는 클래스가 생성되면 DbInterception 클래스를 사용하여 Entity Framework에 등록 할 수 있습니다.

  • IDbCommandInterceptor 인터페이스에는 6 개의 메서드가 있으며 이러한 메서드를 모두 구현해야합니다. 다음은 이러한 메서드의 기본 구현입니다.

IDbCommandInterceptor 인터페이스가 구현 된 다음 코드를 살펴 보겠습니다.

public class MyCommandInterceptor : IDbCommandInterceptor {

   public static void Log(string comm, string message) {
      Console.WriteLine("Intercepted: {0}, Command Text: {1} ", comm, message);
   }

   public void NonQueryExecuted(DbCommand command, 
      DbCommandInterceptionContext<int> interceptionContext) {
         Log("NonQueryExecuted: ", command.CommandText);
   }

   public void NonQueryExecuting(DbCommand command, 
      DbCommandInterceptionContext<int> interceptionContext) {
         Log("NonQueryExecuting: ", command.CommandText);
   }

   public void ReaderExecuted(DbCommand command, 
      DbCommandInterceptionContext<DbDataReader> interceptionContext) {
         Log("ReaderExecuted: ", command.CommandText);
   }

   public void ReaderExecuting(DbCommand command, 
      DbCommandInterceptionContext<DbDataReader> interceptionContext) {
         Log("ReaderExecuting: ", command.CommandText);
   }

   public void ScalarExecuted(DbCommand command, 
      DbCommandInterceptionContext<object> interceptionContext) {
         Log("ScalarExecuted: ", command.CommandText);
   }

   public void ScalarExecuting(DbCommand command, 
      DbCommandInterceptionContext<object> interceptionContext) {
         Log("ScalarExecuting: ", command.CommandText);
   }

}

인터셉터 등록

하나 이상의 차단 인터페이스를 구현하는 클래스가 생성되면 다음 코드와 같이 DbInterception 클래스를 사용하여 EF에 등록 할 수 있습니다.

DbInterception.Add(new MyCommandInterceptor());

인터셉터는 다음 코드와 같이 DbConfiguration 코드 기반 구성을 사용하여 앱 도메인 수준에서 등록 할 수도 있습니다.

public class MyDBConfiguration : DbConfiguration {

   public MyDBConfiguration() {
      DbInterception.Add(new MyCommandInterceptor());
   }
}

코드를 사용하여 인터셉터 구성 파일을 구성 할 수도 있습니다.

<entityFramework>
   <interceptors>
      <interceptor type = "EFInterceptDemo.MyCommandInterceptor, EFInterceptDemo"/>
   </interceptors>
</entityFramework>

공간 형식 지원은 Entity Framework 5에서 도입되었습니다. 쿼리에서 공간 데이터를 분석 할 수 있도록 연산자 집합도 포함되어 있습니다. 예를 들어 쿼리는 두 지리적 위치 간의 거리를 기준으로 필터링 할 수 있습니다.

  • Entity Framework를 사용하면 새 공간 데이터 형식을 클래스의 속성으로 노출하고 데이터베이스의 공간 열에 매핑 할 수 있습니다.

  • 또한 공간 연산자를 사용하여 데이터베이스에서 수행 된 공간 계산을 기반으로 필터링, 정렬 및 그룹화하는 LINQ 쿼리를 작성할 수도 있습니다.

두 가지 주요 공간 데이터 유형이 있습니다.

  • 지리 데이터 유형은 GPS 위도 및 경도 좌표와 같은 타원 데이터를 저장합니다.

  • 기하학 데이터 유형은 유클리드 (평면) 좌표계를 나타냅니다.

Cricket ground의 다음 예를 살펴 보겠습니다.

Step 1 − 파일 → 새로 만들기 → 프로젝트 메뉴 옵션에서 새 프로젝트를 만듭니다.

Step 2 − 왼쪽 창에서 콘솔 애플리케이션을 선택합니다.

Step 3 − 프로젝트 이름을 마우스 오른쪽 버튼으로 클릭하고 NuGet 패키지 관리…를 선택합니다.

Step 4 − Entity Framework를 설치합니다.

Step 5 − System.Data.Entity 어셈블리에 대한 참조를 추가하고 공간 데이터 유형에 대한 System.Data.Spatial using 문도 추가합니다.

Step 6 − Program.cs 파일에 다음 클래스를 추가합니다.

public class CricketGround {
   public int ID { get; set; }
   public string Name { get; set; }
   public DbGeography Location { get; set; }
}

Step 7 − 엔터티를 정의하는 것 외에도 DbContext에서 파생되고 DbSet <TEntity> 속성을 ​​노출하는 클래스를 정의해야합니다.

Program.cs에서 컨텍스트 정의를 추가합니다.

public partial class CricketGroundContext : DbContext {
   public DbSet<CricketGround> CricketGrounds { get; set; }
}

Step 8 − Main 함수에 다음 코드를 추가하면 두 개의 새로운 CricketGround 객체가 컨텍스트에 추가됩니다.

class Program {

   static void Main(string[] args) {

      using (var context = new CricketGroundContext()) {

         context.CricketGrounds.Add(new CricketGround() {
            Name = "Shalimar Cricket Ground", 
            Location = DbGeography.FromText("POINT(-122.336106 47.605049)"), 
         });

         context.CricketGrounds.Add(new CricketGround() {
            Name = "Marghazar Stadium", Location = DbGeography
               .FromText("POINT(-122.335197 47.646711)"), 
         });

         context.SaveChanges();

         var myLocation = DbGeography.FromText("POINT(-122.296623 47.640405)");

         var cricketGround = (from cg in context.CricketGrounds
            orderby cg.Location.Distance(myLocation) select cg).FirstOrDefault();

         Console.WriteLine("The closest Cricket Ground to you is: {0}.", cricketGround.Name);
      }
   }
}

공간 속성은 DbGeography.FromText 메서드를 사용하여 초기화됩니다. WellKnownText로 표시된 지리 지점이 메서드에 전달 된 다음 데이터를 저장합니다. 그 후 CricketGround 객체는 지정된 위치에서 가장 가까운 위치에서 검색됩니다.

위의 코드가 실행되면 다음과 같은 출력을 받게됩니다.

The closest Cricket Ground to you is: Marghazar Stadium

더 나은 이해를 위해 위의 예를 단계별로 실행하는 것이 좋습니다.

상속을 통해 개발자가 생각하는 방식을 더 잘 반영하고 이러한 모델과 상호 작용하는 데 필요한 작업을 줄이는 복잡한 모델을 만들 수 있습니다. 엔터티에 사용되는 상속은 클래스에 사용되는 상속과 동일한 목적으로 사용되므로 개발자는 이미이 기능이 작동하는 방법에 대한 기본 사항을 알고 있습니다.

다음 예제를 살펴보고 새 콘솔 애플리케이션 프로젝트를 만들어 보겠습니다.

Step 1 − 프로젝트 이름을 마우스 오른쪽 버튼으로 클릭하여 ADO.NET 엔티티 데이터 모델을 추가하고 추가 → 새 항목…을 선택합니다.

Step 2 − 하나의 엔티티를 추가하고 모델 우선 접근 방식 장에 언급 된 모든 단계에 따라 이름을 Person으로 지정합니다.

Step 3 − 다음 이미지와 같이 일부 스칼라 속성을 추가합니다.

Step 4 − 엔티티를 두 개 더 추가합니다. StudentTeacher, 이는 Person Table의 속성을 상속합니다.

Step 5 − 이제 Student 엔티티를 추가하고 다음 이미지와 같이 Base type 콤보 박스에서 Person을 선택합니다.

Step 6 − 마찬가지로 Teacher 엔티티를 추가합니다.

Step 7 − 이제 EnrollmentDate 스칼라 속성을 학생 엔티티에 추가하고 HireDate 속성을 Teacher 엔티티에 추가합니다.

Step 8 − 계속해서 데이터베이스를 생성하겠습니다.

Step 9 − 디자인 화면을 마우스 오른쪽 버튼으로 클릭하고 모델에서 데이터베이스 생성…을 선택합니다.

Step 10− 새 데이터베이스를 생성하려면 New Connection…을 클릭합니다. 다음 대화 상자가 열립니다. 확인을 클릭하십시오.

Step 11− 마침을 클릭합니다. 프로젝트에 * .edmx.sql 파일이 추가됩니다. .sql 파일을 열어 Visual Studio에서 DDL 스크립트를 실행할 수 있습니다. 이제 마우스 오른쪽 버튼을 클릭하고 실행을 선택합니다.

Step 12 − 서버 탐색기로 이동하면 지정된 세 개의 테이블로 데이터베이스가 생성 된 것을 볼 수 있습니다.

Step 13 − 다음 도메인 클래스도 자동으로 생성되는 것을 확인할 수 있습니다.

public partial class Person {
   public int ID { get; set; }
   public string FirstMidName { get; set; }
   public string LastName { get; set; }
}

public partial class Student : Person {
   public System.DateTime EnrollmentDate { get; set; }
}

public partial class Teacher : Person {
   public System.DateTime HireDate { get; set; }
}

다음은 Context 클래스입니다.

public partial class InheritanceModelContainer : DbContext {

   public InheritanceModelContainer() : 
      base("name = InheritanceModelContainer") {}

   protected override void OnModelCreating(DbModelBuilder modelBuilder) {
      throw new UnintentionalCodeFirstException();
   }

   public virtual DbSet<Person> People { get; set; }
}

데이터베이스에 학생 및 교사를 추가 한 다음 데이터베이스에서 검색해 보겠습니다.

class Program {

   static void Main(string[] args) {

      using (var context = new InheritanceModelContainer()) {

         var student = new Student {
            FirstMidName = "Meredith", 
            LastName = "Alonso", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
         };

         context.People.Add(student);

         var student1 = new Student {
            FirstMidName = "Arturo", 
            LastName = "Anand", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
         };

         context.People.Add(student1);

         var techaer = new Teacher {
            FirstMidName = "Peggy", 
            LastName = "Justice", 
            HireDate = DateTime.Parse(DateTime.Today.ToString())
         };

         context.People.Add(techaer);

         var techaer1 = new Teacher {
            FirstMidName = "Yan", 
            LastName = "Li", 
            HireDate = DateTime.Parse(DateTime.Today.ToString())
         };

         context.People.Add(techaer1);
         context.SaveChanges();
      }
   }
}

학생과 교사가 데이터베이스에 추가됩니다. NTo는 학생과 교사를 검색합니다.OfType 메소드를 사용해야하며 지정된 부서와 관련된 학생 및 교사를 반환합니다.

Console.WriteLine("All students in database"); 
Console.WriteLine("");

foreach (var student in context.People.OfType<Student>()) {
   string name = student.FirstMidName + " " + student.LastName;
   Console.WriteLine("ID: {0}, Name: {1}, \tEnrollment Date {2} ", 
      student.ID, name, student.EnrollmentDate.ToString());
}

Console.WriteLine("");
Console.WriteLine("************************************************************ *****");
Console.WriteLine("");
Console.WriteLine("All teachers in database");
Console.WriteLine("");

foreach (var teacher in context.People.OfType<Teacher>()) {
   string name = teacher.FirstMidName + " " + teacher.LastName;
   Console.WriteLine("ID: {0}, Name: {1}, \tHireDate {2} ", 
      teacher.ID, name, teacher.HireDate.ToString()); 
}

Console.WriteLine("");
Console.WriteLine("************************************************************ *****");
Console.ReadKey();

첫 번째 쿼리에서 OfType <Student> ()를 사용하면 HireDate 속성이 Teacher Entity의 일부이고 마찬가지로 EnrollmentDate 속성은 OfType <Teacher> ()를 사용할 때 액세스 할 수 없기 때문에 HireDate에 액세스 할 수 없습니다.

위의 코드가 실행되면 다음과 같은 출력을 받게됩니다.

All students in database
ID: 1, Name: Meredith Alonso,   Enrollment Date 10/30/2015 12:00:00 AM
ID: 2, Name: Arturo Anand,      Enrollment Date 10/30/2015 12:00:00 AM
*****************************************************************  
All teachers in database
ID: 3, Name: Peggy Justice,     HireDate 10/30/2015 12:00:00 AM
ID: 4, Name: Yan Li,    HireDate 10/30/2015 12:00:00 AM
*****************************************************************

더 나은 이해를 위해 위의 예를 단계별로 실행하는 것이 좋습니다.

Entity Framework 5 및 이전 버전의 Entity Framework에서 코드는 .NET Framework의 일부로 제공되는 핵심 라이브러리 (주로 System.Data.Entity.dll)로 분할되었으며 추가 라이브러리 (주로 EntityFramework.dll)가 배포되고 다음 다이어그램과 같이 NuGet을 사용하여 배송되었습니다.

Entity Framework 6에서는 이전에 .NET Framework의 일부였던 핵심 API도 NuGet 패키지의 일부로 제공되고 배포됩니다.

이는 Entity Framework를 오픈 소스로 만드는 데 필요했습니다. 그러나 결과적으로 애플리케이션을 이전 버전의 Entity Framework에서 EF 6으로 마이그레이션하거나 업그레이드해야 할 때마다 애플리케이션을 다시 빌드해야합니다.

애플리케이션이 EF 4.1 이상에서 제공되는 DbContext를 사용하는 경우 마이그레이션 프로세스는 간단합니다. 그러나 응용 프로그램이 ObjectContext이면 약간의 작업이 필요합니다.

기존 애플리케이션을 EF6으로 업그레이드하기 위해 거쳐야하는 다음 단계를 살펴 보겠습니다.

Step 1 − 첫 번째 단계는 .NET Framework 4.5.2를 대상으로하고 나중에 프로젝트를 마우스 오른쪽 버튼으로 클릭하고 속성을 선택하는 것입니다.

Step 2 − 프로젝트를 다시 마우스 오른쪽 버튼으로 클릭하고 NuGet 패키지 관리 ...를 선택합니다.

Step 3− 온라인 탭에서 EntityFramework를 선택하고 설치를 클릭합니다. System.Data.Entity.dll에 대한 어셈블리 참조가 제거되었는지 확인합니다.

EF6 NuGet 패키지를 설치하면 프로젝트에서 System.Data.Entity에 대한 모든 참조가 자동으로 제거됩니다.

Step 4 − EF 디자이너로 생성 된 모델이있는 경우 코드 생성 템플릿도 업데이트하여 EF6 호환 코드를 생성해야합니다.

Step 5 − edmx 파일 아래의 솔루션 탐색기에서 일반적으로 이름이 <edmx_file_name> .tt 및 <edmx_file_name> .Context.tt 인 기존 코드 생성 템플릿을 삭제합니다.

Step 6 − EF 디자이너에서 모델을 열고 디자인 화면을 마우스 오른쪽 버튼으로 클릭 한 다음 코드 생성 항목 추가 ...를 선택합니다.

Step 7 − 적절한 EF 6.x 코드 생성 템플릿을 추가합니다.

또한 EF6 호환 코드를 자동으로 생성합니다.

애플리케이션에서 EF 4.1 이상을 사용하는 경우 DbContext 및 Code First 형식의 네임 스페이스가 변경되지 않았으므로 코드에서 아무것도 변경할 필요가 없습니다.

그러나 응용 프로그램이 이전 버전의 Entity Framework를 사용하는 경우 이전에 System.Data.Entity.dll에 있던 ObjectContext와 같은 유형이 새 네임 스페이스로 이동되었습니다.

Step 8 − EF6에 대해 빌드하려면 using 또는 Import 지시문을 업데이트해야합니다.

네임 스페이스 변경에 대한 일반적인 규칙은 System.Data. *의 모든 형식이 System.Data.Entity.Core. *로 이동하는 것입니다. 다음은 그들 중 일부입니다-

  • System.Data.EntityException ⇒ System.Data.Entity.Core.EntityException
  • System.Data.Objects.ObjectContext ⇒ System.Data.Entity.Core.Objects.ObjectContext;
  • System.Data.Objects.DataClasses.RelationshipManager ⇒ System.Data.Entity.Core.Objects.DataClasses.RelationshipManager;

일부 유형은 대부분의 DbContext 기반 애플리케이션에 직접 사용되지 않기 때문에 Core 네임 스페이스에 있습니다.

  • System.Data.EntityState ⇒ System.Data.Entity.EntityState
  • System.Data.Objects.DataClasses.EdmFunctionAttribute ⇒ System.Data.Entity.DbFunctionAttribute

기존 Entity Framework 프로젝트는 큰 변경없이 Entity Framework 6.0에서 작동합니다.

즉시로드는 한 유형의 항목에 대한 쿼리가 관련 항목도 쿼리의 일부로로드하는 프로세스입니다. 빠른 로딩은 다음을 사용하여 달성됩니다.Include method.

이는 요청한 관련 데이터가 데이터베이스의 쿼리 결과와 함께 반환됨을 의미합니다. 데이터 원본에 대한 연결이 하나 뿐이며 초기 쿼리에서 더 많은 양의 데이터가 반환됩니다.

예를 들어 학생을 쿼리 할 때 등록을 열심히로드합니다. 학생과 등록은 단일 쿼리로 검색됩니다.

각각의 등록을 가진 모든 학생이 즉시로드를 사용하여 데이터베이스에서 검색되는 다음 예제를 살펴 보겠습니다.

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {
         // Load all students and related enrollments
         var students = context.Students
            .Include(s ⇒ s.Enrollments).ToList();
			
         foreach (var student in students) {
            string name = student.FirstMidName + " " + student.LastName;
            Console.WriteLine("ID: {0}, Name: {1}", student.ID, name);
				
            foreach (var enrollment in student.Enrollments) {
               Console.WriteLine("Enrollment ID: {0}, Course ID: {1}", 
                  enrollment.EnrollmentID, enrollment.CourseID);
            }
         }

         Console.ReadKey();
      }
   }
}

위의 코드가 컴파일되고 실행되면 다음과 같은 출력이 표시됩니다.

ID: 1, Name: Ali Alexander
       Enrollment ID: 1, Course ID: 1050
       Enrollment ID: 2, Course ID: 4022
       Enrollment ID: 3, Course ID: 4041
ID: 2, Name: Meredith Alonso
       Enrollment ID: 4, Course ID: 1045
       Enrollment ID: 5, Course ID: 3141
       Enrollment ID: 6, Course ID: 2021
ID: 3, Name: Arturo Anand
       Enrollment ID: 7, Course ID: 1050
ID: 4, Name: Gytis Barzdukas
       Enrollment ID: 8, Course ID: 1050
       Enrollment ID: 9, Course ID: 4022

다음은 사용할 수있는 다른 형태의 eager loading 쿼리입니다.

// Load one Student and its related enrollments

var student1 = context.Students
   .Where(s ⇒ s.FirstMidName == "Ali")
   .Include(s ⇒ s.Enrollments).FirstOrDefault();

// Load all Students and related enrollments
// using a string to specify the relationship

var studentList = context.Students
   .Include("Enrollments").ToList();

// Load one Student and its related enrollments
// using a string to specify the relationship

var student = context.Students
   .Where(s ⇒ s.FirstMidName == "Salman")
   .Include("Enrollments").FirstOrDefault();

여러 수준

여러 수준의 관련 엔터티를 열심히로드 할 수도 있습니다. 다음 쿼리는 학생, 등록 및 과정의 예를 보여줍니다.

// Load all Students, all related enrollments, and all related courses

var studentList = context.Students
   .Include(s ⇒ s.Enrollments.Select(c ⇒ c.Course)).ToList();

// Load all Students, all related enrollments, and all related courses
// using a string to specify the relationships

var students = context.Students
   .Include("Enrollments.Course").ToList();

더 나은 이해를 위해 위의 예를 단계별로 실행하는 것이 좋습니다.

지연로드는 엔티티 / 엔티티를 참조하는 속성에 처음 액세스 할 때 엔티티 또는 엔티티 컬렉션이 데이터베이스에서 자동으로로드되는 프로세스입니다. 지연로드는 특별히 요청할 때까지 관련 데이터의로드를 지연시키는 것을 의미합니다.

  • POCO 엔터티 유형을 사용하는 경우 파생 된 프록시 유형의 인스턴스를 만든 다음 가상 속성을 재정 의하여로드 후크를 추가하면 지연로드가 수행됩니다.

  • 지연 로딩은 거의 기본값입니다.

  • 기본 구성을 그대로두고 지연로드 이외의 다른 것을 원한다고 쿼리에서 Entity Framework에 명시 적으로 지정하지 않으면 지연로드가 제공됩니다.

  • 예를 들어 Student 엔터티 클래스를 사용하는 경우 Enrollments 탐색 속성에 처음 액세스 할 때 관련 Enrollments가로드됩니다.

  • 탐색 속성은 공개, 가상으로 정의되어야합니다. 컨텍스트는NOT 속성이 가상으로 정의되지 않은 경우 지연로드를 수행합니다.

다음은 Enrollments의 탐색 속성을 포함하는 Student 클래스입니다.

public partial class Student {

   public Student() {
      this.Enrollments = new HashSet<Enrollment>();
   }
	
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public System.DateTime EnrollmentDate { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

먼저 데이터베이스에서 학생 목록을로드 한 다음 필요할 때마다 특정 학생의 등록을로드하는 간단한 예를 살펴 보겠습니다.

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         //Loading students only
         IList<Student> students = context.Students.ToList<Student>();

         foreach (var student in students) {

            string name = student.FirstMidName + " " + student.LastName;
            Console.WriteLine("ID: {0}, Name: {1}", student.ID, name);
	
            foreach (var enrollment in student.Enrollments) {
               Console.WriteLine("Enrollment ID: {0}, Course ID: {1}", 
                  enrollment.EnrollmentID, enrollment.CourseID);
            }
         }

         Console.ReadKey();
      }
   }
}

위의 코드가 컴파일되고 실행되면 다음과 같은 출력이 표시됩니다.

ID: 1, Name: Ali Alexander
       Enrollment ID: 1, Course ID: 1050
       Enrollment ID: 2, Course ID: 4022
       Enrollment ID: 3, Course ID: 4041
ID: 2, Name: Meredith Alonso
       Enrollment ID: 4, Course ID: 1045
       Enrollment ID: 5, Course ID: 3141
       Enrollment ID: 6, Course ID: 2021
ID: 3, Name: Arturo Anand
       Enrollment ID: 7, Course ID: 1050
ID: 4, Name: Gytis Barzdukas
       Enrollment ID: 8, Course ID: 1050
       Enrollment ID: 9, Course ID: 4022
ID: 5, Name: Yan Li
       Enrollment ID: 10, Course ID: 4041
ID: 6, Name: Peggy Justice
       Enrollment ID: 11, Course ID: 1045
ID: 7, Name: Laura Norman
       Enrollment ID: 12, Course ID: 3141

지연 로딩 끄기

지연로드와 직렬화는 잘 섞이지 않으며주의하지 않으면 지연로드가 활성화되어 있기 때문에 전체 데이터베이스에 대한 쿼리를 끝낼 수 있습니다. 엔터티를 직렬화하기 전에 지연로드를 해제하는 것이 좋습니다.

특정 탐색 속성 끄기

다음 예제와 같이 Enrollments 속성을 가상이 아닌 상태로 만들면 Enrollments 컬렉션의 지연로드를 끌 수 있습니다.

public partial class Student { 

   public Student() { 
      this.Enrollments = new HashSet<Enrollment>(); 
   }
	
   public int ID { get; set; } 
   public string LastName { get; set; } 
   public string FirstMidName { get; set; } 
   public System.DateTime EnrollmentDate { get; set; }
   public ICollection<Enrollment> Enrollments { get; set; } 
}

모든 엔티티에 대해 끄기

다음 예제와 같이 Configuration 속성의 플래그를 false로 설정하여 컨텍스트의 모든 엔터티에 대해 지연로드를 해제 할 수 있습니다.

public partial class UniContextEntities : DbContext { 

   public UniContextEntities(): base("name=UniContextEntities") {
      this.Configuration.LazyLoadingEnabled = false;
   }
	
   protected override void OnModelCreating(DbModelBuilder modelBuilder) { 
      throw new UnintentionalCodeFirstException(); 
   } 
}

지연로드를 끈 후 위의 예를 다시 실행하면 등록이로드되지 않고 학생 데이터 만 검색되는 것을 볼 수 있습니다.

ID: 1, Name: Ali Alexander
ID: 2, Name: Meredith Alons
ID: 3, Name: Arturo Anand
ID: 4, Name: Gytis Barzduka
ID: 5, Name: Yan Li
ID: 6, Name: Peggy Justice
ID: 7, Name: Laura Norman
ID: 8, Name: Nino Olivetto

더 나은 이해를 위해 위의 예를 단계별로 실행하는 것이 좋습니다.

지연로드를 비활성화 한 경우에도 관련 항목을 지연로드 할 수 있지만 명시 적 호출로 수행해야합니다.

  • 지연로드와 달리 쿼리 실행시기와 관련하여 모호하거나 혼동 될 가능성이 없습니다.

  • 이렇게하려면 관련 엔터티 항목에 Load 메서드를 사용합니다.

  • 일대 다 관계의 경우 Collection에서 Load 메서드를 호출합니다.

  • 일대일 관계의 경우 참조에서 Load 메서드를 호출합니다.

지연 로딩이 비활성화 된 다음 예제를 살펴보면 이름이 Ali 인 학생이 검색됩니다.

그런 다음 학생 정보가 콘솔에 기록됩니다. 코드를 보면 등록 정보도 작성되지만 Enrollments 엔터티가 아직로드되지 않았으므로 foreach 루프가 실행되지 않습니다.

Enrollments 엔터티가 명시 적으로로드되면 이제 학생 정보와 등록 정보가 콘솔 창에 기록됩니다.

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         context.Configuration.LazyLoadingEnabled = false;

         var student = (from s in context.Students where s.FirstMidName == 
            "Ali" select s).FirstOrDefault<Student>();

         string name = student.FirstMidName + " " + student.LastName;
         Console.WriteLine("ID: {0}, Name: {1}", student.ID, name);

         foreach (var enrollment in student.Enrollments) {
            Console.WriteLine("Enrollment ID: {0}, Course ID: {1}", 
               enrollment.EnrollmentID, enrollment.CourseID);
         }

         Console.WriteLine();
         Console.WriteLine("Explicitly loaded Enrollments");
         Console.WriteLine();

         context.Entry(student).Collection(s ⇒ s.Enrollments).Load();
         Console.WriteLine("ID: {0}, Name: {1}", student.ID, name);

         foreach (var enrollment in student.Enrollments) {
            Console.WriteLine("Enrollment ID: {0}, Course ID: {1}", 
               enrollment.EnrollmentID, enrollment.CourseID);
         }

         Console.ReadKey();
      }
   }
}

위의 예제가 실행되면 다음과 같은 출력이 표시됩니다. 먼저 학생 정보 만 표시되고 등록 엔터티를 명시 적으로로드 한 후 학생 및 관련 등록 정보가 모두 표시됩니다.

ID: 1, Name: Ali Alexander
Explicitly loaded Enrollments
ID: 1, Name: Ali Alexander
       Enrollment ID: 1, Course ID: 1050
       Enrollment ID: 2, Course ID: 4022
       Enrollment ID: 3, Course ID: 4041

더 나은 이해를 위해 위의 예를 단계별로 실행하는 것이 좋습니다.

이 장에서는 모델 데이터의 유효성을 검사하기 위해 ADO.NET Entity Framework에서 사용할 수있는 유효성 검사 기술에 대해 알아 봅니다. Entity Framework는 클라이언트 쪽 유효성 검사를 위해 사용자 인터페이스에 구현하거나 서버 쪽 유효성 검사에 사용할 수있는 매우 다양한 유효성 검사 기능을 제공합니다.

  • Entity Framework에서 데이터 유효성 검사는 응용 프로그램에서 잘못된 데이터를 포착하기위한 솔루션의 일부입니다.

  • Entity Framework는 광범위한 데이터 유효성 검사 방법을 사용하여 기본적으로 데이터베이스에 기록되기 전에 모든 데이터의 유효성을 검사합니다.

  • 그러나 Entity Framework는 사용자 인터페이스 데이터 유효성 검사 후에 제공됩니다. 따라서이 경우 EF에서 발생하는 예외를 처리하고 일반 메시지를 표시하기 위해 엔터티 유효성 검사가 필요합니다.

  • 오류 검사를 개선하고 오류 메시지를 사용자에게 다시 전달하는 방법을위한 데이터 유효성 검사 기술이 있습니다.

DbContext에는 ValidateEntity라는 Overridable 메서드가 있습니다. SaveChanges를 호출하면 Entity Framework는 상태가 Unchanged가 아닌 캐시의 각 엔터티에 대해이 메서드를 호출합니다. Student Entity에 대한 다음 예제와 같이 여기에 유효성 검사 논리를 직접 넣을 수 있습니다.

public partial class UniContextEntities : DbContext {

   protected override System.Data.Entity.Validation
      .DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, 
      System.Collections.Generic.IDictionary<object, object> items) {

         if (entityEntry.Entity is Student) {

            if (entityEntry.CurrentValues.GetValue<string>("FirstMidName") == "") {

               var list = new List<System.Data.Entity
                  .Validation.DbValidationError>();

               list.Add(new System.Data.Entity.Validation
                  .DbValidationError("FirstMidName", "FirstMidName is required"));

               return new System.Data.Entity.Validation
                  .DbEntityValidationResult(entityEntry, list);
            }
         }

         if (entityEntry.CurrentValues.GetValue<string>("LastName") == "") {

            var list = new List<System.Data.Entity
               .Validation.DbValidationError>();

            list.Add(new System.Data.Entity.Validation
               .DbValidationError("LastName", "LastName is required"));

            return new System.Data.Entity.Validation
               .DbEntityValidationResult(entityEntry, list);
         }

         return base.ValidateEntity(entityEntry, items);
   }
}

위 ValidateEntity 메서드에서 Student 엔터티 FirstMidName 및 LastName 속성은 이러한 속성에 빈 문자열이있는 경우 확인 된 다음 오류 메시지를 반환합니다.

새로운 학생이 생성되었지만 다음 코드와 같이 학생의 FirstMidName이 빈 문자열 인 간단한 예를 살펴 보겠습니다.

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         Console.WriteLine("Adding new Student to the database");
         Console.WriteLine();

         try {

            context.Students.Add(new Student() {
               FirstMidName = "",
               LastName = "Upston"
            });

            context.SaveChanges();
         } catch (DbEntityValidationException dbValidationEx) {

            foreach (DbEntityValidationResult entityErr in 
               dbValidationEx.EntityValidationErrors) {

               foreach (DbValidationError error in entityErr.ValidationErrors) {
                  Console.WriteLine("Error: {0}",error.ErrorMessage);
               }
            }
         }

         Console.ReadKey();
      }
   }
}

위의 예제를 컴파일하고 실행하면 콘솔 창에 다음과 같은 오류 메시지가 나타납니다.

Adding new Student to the database  
Error: FirstMidName is required

더 나은 이해를 위해 위의 예를 단계별로 실행하는 것이 좋습니다.

Entity Framework는 엔터티 및 해당 관계에 대한 변경 내용을 추적하는 기능을 제공하므로 컨텍스트의 SaveChanges 메서드가 호출 될 때 데이터베이스에서 올바른 업데이트가 수행됩니다. 이것은 Entity Framework의 핵심 기능입니다.

  • 변경 내용 추적은 엔터티 컬렉션에 새 레코드를 추가하거나 기존 엔터티를 수정 또는 제거하는 동안 변경 사항을 추적합니다.

  • 그런 다음 모든 변경 사항은 DbContext 수준에서 유지됩니다.

  • 이러한 트랙 변경 사항은 DbContext 개체가 삭제되기 전에 저장되지 않으면 손실됩니다.

  • DbChangeTracker 클래스는 컨텍스트에 의해 추적되는 현재 엔터티에 대한 모든 정보를 제공합니다.

  • 컨텍스트별로 엔터티를 추적하려면 기본 키 속성이 있어야합니다.

Entity Framework에서 변경 내용 추적은 기본적으로 사용됩니다. DbContext의 AutoDetectChangesEnabled 속성을 false로 설정하여 변경 내용 추적을 비활성화 할 수도 있습니다. 이 속성을 true로 설정하면 Entity Framework가 엔터티 상태를 유지합니다.

using (var context = new UniContextEntities()) {
   context.Configuration.AutoDetectChangesEnabled = true;
}

학생과 등록이 데이터베이스에서 검색되는 다음 예를 살펴 보겠습니다.

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         context.Configuration.AutoDetectChangesEnabled = true;
         Console.WriteLine("Retrieve Student");

         var student = (from s in context.Students where s.FirstMidName == 
            "Ali" select s).FirstOrDefault<Student>();

         string name = student.FirstMidName + " " + student.LastName;
         Console.WriteLine("ID: {0}, Name: {1}", student.ID, name);
         Console.WriteLine();
         Console.WriteLine("Retrieve all related enrollments");

         foreach (var enrollment in student.Enrollments) {
            Console.WriteLine("Enrollment ID: {0}, Course ID: {1}", 
               enrollment.EnrollmentID, enrollment.CourseID);
         }

         Console.WriteLine();

         Console.WriteLine("Context tracking changes of {0} entity.", 
            context.ChangeTracker.Entries().Count());

         var entries = context.ChangeTracker.Entries();

         foreach (var entry in entries) {
            Console.WriteLine("Entity Name: {0}", entry.Entity.GetType().Name);
            Console.WriteLine("Status: {0}", entry.State);
         }

         Console.ReadKey();
      }
   }
}

위의 예제가 컴파일되고 실행되면 다음과 같은 출력이 표시됩니다.

Retrieve Student 
ID: 1, Name: Ali Alexander
Retrieve all related enrollments
       Enrollment ID: 1, Course ID: 1050
       Enrollment ID: 2, Course ID: 4022
       Enrollment ID: 3, Course ID: 4041
Context tracking changes of 4 entity.
Entity Name: Student
Status: Unchanged
Entity Name: Enrollment
Status: Unchanged
Entity Name: Enrollment
Status: Unchanged
Entity Name: Enrollment
Status: Unchanged

모든 데이터는 데이터베이스에서만 검색되므로 모든 엔터티에 대해 상태가 변경되지 않습니다.

이제 등록을 하나 더 추가하고 데이터베이스에서 한 학생을 삭제하는 또 다른 간단한 예를 살펴 보겠습니다. 다음은 새 등록이 추가되고 한 명의 학생이 삭제되는 코드입니다.

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         context.Configuration.AutoDetectChangesEnabled = true;

         Enrollment enr = new Enrollment() { 
            StudentID = 1, CourseID = 3141 
         };

         Console.WriteLine("Adding New Enrollment");
         context.Enrollments.Add(enr);
         Console.WriteLine("Delete Student");

         var student = (from s in context.Students where s.ID == 
            23 select s).SingleOrDefault<Student>();

         context.Students.Remove(student);
         Console.WriteLine("");

         Console.WriteLine("Context tracking changes of {0} entity.", 
            context.ChangeTracker.Entries().Count());
         var entries = context.ChangeTracker.Entries();

         foreach (var entry in entries) {
            Console.WriteLine("Entity Name: {0}", entry.Entity.GetType().Name);
            Console.WriteLine("Status: {0}", entry.State);
         }

         Console.ReadKey();
      }
   }
}

위의 예제를 컴파일하고 실행하면 다음과 같은 출력을 받게됩니다.

Adding New Enrollment
Delete Student
Context tracking changes of 2 entity.
Entity Name: Enrollment
Status: Added
Entity Name: Student
Status: Deleted

이제 등록 엔터티의 상태가 추가됨으로 설정되고 학생 엔터티의 상태가 삭제되었음을 확인할 수 있습니다. 새 등록이 추가되고 한 명의 학생이 데이터베이스에서 제거 되었기 때문입니다.

더 나은 이해를 위해 위의 예를 단계별로 실행하는 것이 좋습니다.

Entity Framework에서 컬러 엔터티는 주로 디자이너에서 엔터티의 색을 변경하여 개발자가 Visual Studio 디자이너에서 관련 엔터티 그룹을 쉽게 식별 할 수 있도록합니다. 이 기능은 Entity Framework 5.0에서 처음 도입되었습니다.

  • 이 기능은 성능 측면과 관련이 없습니다.

  • 하나의 edmx 파일에 대규모 프로젝트와 많은 엔티티가있는 경우이 기능은 다른 모듈에서 엔티티를 분리하는 데 매우 유용합니다.

edmx 파일로 작업하고 디자이너에서 파일을 연 경우 색상을 변경하려면 디자인 창에서 엔티티를 선택합니다. 그런 다음 마우스 오른쪽 버튼을 클릭하고 속성을 선택합니다.

속성 창에서 채우기 색 속성을 선택합니다.

유효한 색상 이름 (예 : 녹색 또는 유효한 RGB (255, 128, 128))을 사용하여 색상을 지정하거나 색상 선택기에서 선택할 수도 있습니다.

한 번에 여러 엔티티의 색상을 변경하려면 여러 엔티티를 선택하고 속성 창을 사용하여 모든 엔티티의 채우기 색상을 변경합니다.

다음 옵션 중 하나를 선택하여 속성 형식을 변경할 수도 있습니다.

  • 이름 표시하기
  • 표시 이름 및 유형

기본적으로 표시 이름 옵션이 선택됩니다. 속성 형식을 변경하려면 디자이너 창을 마우스 오른쪽 버튼으로 클릭합니다.

스칼라 속성 형식 → 표시 이름 및 유형을 선택합니다.

이제 유형이 이름과 함께 표시되는 것을 볼 수 있습니다.

Entity Framework는 엔터티 모델을 만드는 세 가지 접근 방식을 제공하며 각 접근 방식에는 고유 한 장단점이 있습니다.

  • 코드 우선
  • 데이터베이스 우선
  • 먼저 모델

이 장에서는 코드 우선 접근 방식에 대해 간략하게 설명합니다. 일부 개발자는 코드에서 디자이너로 작업하는 것을 선호하는 반면 다른 개발자는 코드로 작업하는 것을 선호합니다. 이러한 개발자를 위해 Entity Framework에는 Code First라고하는 모델링 워크 플로가 있습니다.

  • Code First 모델링 워크 플로우는 존재하지 않는 데이터베이스를 대상으로하며 Code First가이를 생성합니다.

  • 빈 데이터베이스가있는 경우에도 사용할 수 있으며 Code First는 여기에 새 테이블을 추가합니다.

  • Code First를 사용하면 C # 또는 VB.Net 클래스를 사용하여 모델을 정의 할 수 있습니다.

  • 추가 구성은 클래스 및 속성의 속성을 사용하거나 유창한 API를 사용하여 선택적으로 수행 할 수 있습니다.

왜 코드 우선인가?

  • Code First는 실제로 퍼즐 조각 세트로 구성되어 있습니다. 첫 번째는 도메인 클래스입니다.

  • 도메인 클래스는 Entity Framework와 관련이 없습니다. 비즈니스 도메인의 항목 일뿐입니다.

  • 그러면 Entity Framework에는 이러한 클래스와 데이터베이스 간의 상호 작용을 관리하는 컨텍스트가 있습니다.

  • 컨텍스트는 Code First에만 국한되지 않습니다. Entity Framework 기능입니다.

  • Code First는 컨텍스트가 관리하는 클래스를 검사 한 다음 일련의 규칙 또는 규칙을 사용하여 해당 클래스와 관계가 모델을 설명하는 방법과 해당 모델이 데이터베이스에 매핑되는 방법을 결정하는 모델 빌더를 추가합니다.

  • 이 모든 것은 런타임에 발생합니다. 이 모델은 결코 볼 수 없으며 단지 메모리에 있습니다.

  • Code First는 원하는 경우 해당 모델을 사용하여 데이터베이스를 만들 수도 있습니다.

  • Code First Migrations라는 기능을 사용하여 모델이 변경되면 데이터베이스를 업데이트 할 수도 있습니다.

환경 설정

EF Code First 접근 방식으로 작업을 시작하려면 시스템에 다음 도구를 설치해야합니다.

  • Visual Studio 2013 (.net framework 4.5.2) 이상 버전.
  • MS SQL Server 2012 이상.
  • NuGet 패키지를 통한 Entity Framework.

NuGet 패키지를 통해 EF 설치

Step 1 − 먼저 파일 → 새로 만들기 → 프로젝트…에서 콘솔 응용 프로그램을 만듭니다.

Step 2 − 왼쪽 창에서 Windows를 선택하고 템플릿 창에서 Console Application을 선택합니다.

Step 3 − 이름으로 EFCodeFirstDemo를 입력하고 확인을 선택합니다.

Step 4 − 솔루션 탐색기에서 프로젝트를 마우스 오른쪽 버튼으로 클릭하고 NuGet 패키지 관리…를 선택합니다.

NuGet 패키지 관리자가 열리고 EntityFramework를 검색합니다. 그러면 Entity Framework와 관련된 모든 패키지가 검색됩니다.

Step 5− EntityFramework를 선택하고 설치를 클릭합니다. 또는 도구 메뉴에서 NuGet 패키지 관리자를 클릭 한 다음 패키지 관리자 콘솔을 클릭합니다. 패키지 관리자 콘솔 창에서 다음 명령을 입력하십시오. Install-Package EntityFramework.

설치가 완료되면 "EFCodeFirstDemo에 'EntityFramework 6.1.2'를 성공적으로 설치했습니다."라는 출력 창에 다음 메시지가 표시됩니다.

설치 후에는 다음 이미지와 같이 EntityFramework.dll이 프로젝트에 포함됩니다.

이제 Code First 접근 방식을 시작할 준비가되었습니다.

클래스를 사용하여 매우 간단한 모델을 정의 해 봅시다. Program.cs 파일에서 정의하고 있지만 실제 응용 프로그램에서는 클래스를 별도의 파일과 잠재적으로 별도의 프로젝트로 분할합니다. 다음은 Code First 접근 방식을 사용하여 생성 할 데이터 모델입니다.

모델 생성

Student 클래스에 대해 다음 코드를 사용하여 Program.cs 파일에 다음 세 가지 클래스를 추가합니다.

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}
  • ID 속성은이 클래스에 해당하는 데이터베이스 테이블의 기본 키 열이됩니다.

  • Enrollments 속성은 탐색 속성입니다. 탐색 속성에는이 엔터티와 관련된 다른 엔터티가 포함됩니다.

  • 이 경우 Student 엔터티의 Enrollments 속성에는 해당 Student 엔터티와 관련된 모든 Enrollment 엔터티가 포함됩니다.

  • 탐색 속성은 일반적으로 가상으로 정의되므로 지연로드와 같은 특정 Entity Framework 기능을 활용할 수 있습니다.

  • 탐색 속성이 여러 엔터티를 보유 할 수있는 경우 (다 대다 또는 일토 마니 관계에서와 같이) 해당 유형은 ICollection과 같이 항목을 추가, 삭제 및 업데이트 할 수있는 목록이어야합니다.

다음은 Course 클래스의 구현입니다.

public class Course {
   public int CourseID { get; set; }
   public string Title { get; set; }
   public int Credits { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

Enrollments 속성은 탐색 속성입니다. 과정 엔터티는 여러 등록 엔터티와 관련 될 수 있습니다.

다음은 Enrollment 클래스 및 enum에 대한 구현입니다.

public enum Grade {
   A, B, C, D, F
}

public class Enrollment {
   public int EnrollmentID { get; set; }
   public int CourseID { get; set; }
   public int StudentID { get; set; }
   public Grade? Grade { get; set; }
	
   public virtual Course Course { get; set; }
   public virtual Student Student { get; set; }
}
  • EnrollmentID 속성이 기본 키가됩니다.

  • Grade 속성은 열거 형입니다. Grade 유형 선언 뒤의 물음표는 Grade 속성이 nullable임을 나타냅니다.

  • null 인 등급은 0 등급과 다릅니다. Null은 성적이 알려지지 않았거나 아직 할당되지 않았 음을 의미합니다.

  • StudentID 및 CourseID 속성은 외래 키이며 해당 탐색 속성은 Student 및 Course입니다.

  • Enrollment 엔터티는 하나의 Student 및 하나의 Course 엔터티와 연결되므로 속성은 하나의 Student 및 Course 엔터티 만 보유 할 수 있습니다.

데이터베이스 컨텍스트 생성

지정된 데이터 모델에 대한 Entity Framework 기능을 조정하는 기본 클래스는 데이터를 쿼리하고 저장할 수있는 데이터베이스 컨텍스트 클래스입니다. DbContext 클래스에서 파생하고 형식화 된 DbSet을 노출하여이 클래스를 만들 수 있습니다. 모델의 각 클래스에 대해. 다음은 DbContext 클래스에서 파생 된 MyContext 클래스의 구현입니다.

public class MyContext : DbContext {
   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }
}

다음은 Program.cs 파일의 전체 코드입니다.

using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EFCodeFirstDemo {

   class Program {
      static void Main(string[] args) {}
   }

   public enum Grade {
      A, B, C, D, F
   }

   public class Enrollment {
      public int EnrollmentID { get; set; }
      public int CourseID { get; set; }
      public int StudentID { get; set; }
      public Grade? Grade { get; set; }
		
      public virtual Course Course { get; set; }
      public virtual Student Student { get; set; }
   }

   public class Student {
      public int ID { get; set; }
      public string LastName { get; set; }
      public string FirstMidName { get; set; }
      public DateTime EnrollmentDate { get; set; }
		
      public virtual ICollection<Enrollment> Enrollments { get; set; }
   }

   public class Course {
      public int CourseID { get; set; }
      public string Title { get; set; }
      public int Credits { get; set; }
		
      public virtual ICollection<Enrollment> Enrollments { get; set; }
   }

   public class MyContext : DbContext {
      public virtual DbSet<Course> Courses { get; set; }
      public virtual DbSet<Enrollment> Enrollments { get; set; }
      public virtual DbSet<Student> Students { get; set; }
   }

}

위의 코드는 데이터 저장 및 검색을 시작하는 데 필요한 전부입니다. 데이터를 추가 한 다음 검색해 보겠습니다. 다음은 주요 방법의 코드입니다.

static void Main(string[] args) {

   using (var context = new MyContext()) {
      // Create and save a new Students
      Console.WriteLine("Adding new students");

      var student = new Student {
         FirstMidName = "Alain", LastName = "Bomer", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
      };

      context.Students.Add(student);
		
      var student1 = new Student {
         FirstMidName = "Mark", LastName = "Upston", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
      };

      context.Students.Add(student1);
      context.SaveChanges();

      // Display all Students from the database
      var students = (from s in context.Students 
         orderby s.FirstMidName select s).ToList<Student>();

      Console.WriteLine("Retrieve all Students from the database:");

      foreach (var stdnt in students) {
         string name = stdnt.FirstMidName + " " + stdnt.LastName;
         Console.WriteLine("ID: {0}, Name: {1}", stdnt.ID, name);
      }
		
      Console.WriteLine("Press any key to exit...");
      Console.ReadKey();
   }
}

위의 코드가 실행되면 다음과 같은 출력을 받게됩니다.

Adding new students
Retrieve all Students from the database:
ID: 1, Name: Alain Bomer
ID: 2, Name: Mark Upston
Press any key to exit...

이제 떠오르는 질문은 우리가 데이터를 추가 한 다음 데이터베이스에서 검색 한 데이터와 데이터베이스는 어디에 있습니까? 규칙에 따라 DbContext는 데이터베이스를 생성했습니다.

  • 로컬 SQL Express 인스턴스를 사용할 수있는 경우 Code First는 해당 인스턴스에 데이터베이스를 생성 한 것입니다.

  • SQL Express를 사용할 수없는 경우 Code First는 LocalDb를 사용합니다.

  • 데이터베이스는 파생 된 컨텍스트의 정규화 된 이름을 따서 명명됩니다.

이 경우 SQL Express 인스턴스를 사용할 수 있으며 다음 이미지와 같이 데이터베이스 이름은 EFCodeFirstDemo.MyContext입니다.

  • 이것은 기본 규칙 일 뿐이며 Code First가 사용하는 데이터베이스를 변경하는 다양한 방법이 있습니다.

  • 위 이미지에서 볼 수 있듯이 Student, Courses 및 Enrollments 테이블이 생성되었으며 각 테이블에는 적절한 데이터 유형과 길이가있는 열이 포함되어 있습니다.

  • 열 이름과 데이터 유형은 각 도메인 클래스의 속성과도 일치합니다.

데이터베이스 초기화

위의 예에서는 Code First가 데이터베이스를 자동으로 생성하는 것을 보았지만 데이터베이스 및 서버의 이름을 변경하려면 Code First가 데이터베이스를 초기화하는 동안 데이터베이스 이름과 서버를 결정하는 방법을 살펴 보겠습니다. 다음 다이어그램을 살펴보십시오.

다음과 같은 방법으로 컨텍스트 클래스의 기본 생성자를 정의 할 수 있습니다.

  • 매개 변수 없음
  • 데이터베이스 이름
  • 연결 문자열 이름

매개 변수 없음

위의 예와 같이 매개 변수없이 컨텍스트 클래스의 기본 생성자를 지정하면 엔티티 프레임 워크는 이름이 {Namespace}. {Context class name} 인 로컬 SQLEXPRESS 서버에 데이터베이스를 생성합니다.

위의 예에서 자동으로 생성되는 데이터베이스의 이름은 EFCodeFirstDemo.MyContext입니다. 이름을 보면 다음 코드와 같이 EFCodeFirstDemo가 네임 스페이스이고 MyContext가 컨텍스트 클래스 이름임을 알 수 있습니다.

public class MyContext : DbContext {
   public MyContext() : base() {}

   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }
}

데이터베이스 이름

컨텍스트 클래스의 기본 생성자에서 데이터베이스 이름을 매개 변수로 전달하면 Code First는 자동으로 데이터베이스를 다시 생성하지만 이번에는 로컬 SQLEXPRESS 데이터베이스 서버의 기본 생성자에서 매개 변수로 전달되는 이름이됩니다. .

다음 코드에서 MyContextDB는 기본 생성자에서 매개 변수로 지정됩니다. 애플리케이션을 실행하면 MyContextDB 이름의 데이터베이스가 로컬 SQL 서버에 생성됩니다.

public class MyContext : DbContext {
   public MyContext() : base("MyContextDB") {}
   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }
}

연결 문자열 이름

이것은 DbContext에 SQL Express 또는 LocalDb 이외의 데이터베이스 서버를 사용하도록 지시하는 쉬운 방법입니다. app.config 파일에 연결 문자열을 넣도록 선택할 수 있습니다.

  • 연결 문자열의 이름이 컨텍스트 이름과 일치하면 (네임 스페이스 한정 여부에 관계없이) DbContext는 매개 변수 less 생성자를 사용할 때이를 찾습니다.

  • 연결 문자열 이름이 컨텍스트 이름과 다른 경우 DbContext 생성자에 연결 문자열 이름을 전달하여 코드 우선 모드에서이 연결을 사용하도록 DbContext에 지시 할 수 있습니다.

public class MyContext : DbContext {
   public MyContext() : base("name = MyContextDB") {}
   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }
}
  • 위 코드에서 컨텍스트 클래스 연결 문자열의 스 니펫은 기본 생성자에서 매개 변수로 지정됩니다.

  • 연결 문자열 이름은 "name ="으로 시작해야합니다. 그렇지 않으면 데이터베이스 이름으로 간주됩니다.

  • 이 형식은 구성 파일에서 연결 문자열을 찾을 것으로 예상 함을 명시합니다. 주어진 이름의 연결 문자열을 찾을 수 없으면 예외가 발생합니다.

<connectionStrings>
   <add name = "MyContextDB"
      connectionString = "Data Source =.;Initial Catalog = EFMyContextDB;Integrated Security = true"
      providerName = "System.Data.SqlClient"/>
</connectionStrings>
  • app.config의 연결 문자열에있는 데이터베이스 이름은 다음과 같습니다. EFMyContextDB. CodeFirst는 새로운EFMyContextDB 데이터베이스 또는 기존 사용 EFMyContextDB 로컬 SQL Server의 데이터베이스.

도메인 클래스

지금까지 EF가 기본 규칙을 사용하여 모델을 검색하도록했지만 클래스가 규칙을 따르지 않고 추가 구성을 수행 할 수 있어야하는 경우가 있습니다. 그러나 EF에 필요한 정보를 제공하도록 도메인 클래스를 구성하여 이러한 규칙을 재정의 할 수 있습니다. 도메인 클래스를 구성하는 두 가지 옵션이 있습니다-

  • 데이터 주석
  • Fluent API

데이터 주석

DataAnnotations는 가장 일반적으로 필요한 구성을 강조하는 클래스를 구성하는 데 사용됩니다. DataAnnotations는 ASP.NET MVC와 같은 여러 .NET 응용 프로그램에서도 이해되며, 이러한 응용 프로그램은 클라이언트 측 유효성 검사에 동일한 주석을 활용할 수 있습니다.

다음은 학생 수업에서 사용되는 데이터 주석입니다.

public class Enrollment {

   [Key]
   public int EnrollmentID { get; set; }
   public int CourseID { get; set; }
   public int StudentID { get; set; }
   public Grade? Grade { get; set; }

   [ForeignKey("CourseID")]
   public virtual Course Course { get; set; }

   [ForeignKey("ID")]
   public virtual Student Student { get; set; }
}

Fluent API

대부분의 모델 구성은 간단한 데이터 주석을 사용하여 수행 할 수 있습니다. Fluent API는 데이터 주석으로 수행 할 수없는 일부 고급 구성 외에도 데이터 주석으로 수행 할 수있는 모든 작업을 포함하는 모델 구성을 지정하는 고급 방법입니다. 데이터 주석과 유창한 API를 함께 사용할 수 있습니다.

유창한 API에 액세스하려면 DbContext에서 OnModelCreating 메서드를 재정의합니다. 이제 다음 코드와 같이 student 테이블의 열 이름을 FirstMidName에서 FirstName으로 바꿉니다.

public class MyContext : DbContext {

   protected override void OnModelCreating(DbModelBuilder modelBuilder) {
      modelBuilder.Entity<Student>().Property(s ⇒ s.FirstMidName)
         .HasColumnName("FirstName");
   }

   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }
}

DataAnnotations는 가장 일반적으로 필요한 구성을 강조하는 클래스를 구성하는 데 사용됩니다. DataAnnotations는 ASP.NET MVC와 같은 여러 .NET 응용 프로그램에서도 이해되며 이러한 응용 프로그램은 클라이언트 측 유효성 검사에 동일한 주석을 활용할 수 있습니다. DataAnnotation 속성은 기본 CodeFirst 규칙을 재정의합니다.

System.ComponentModel.DataAnnotations Null 허용 여부 또는 열 크기에 영향을주는 다음 속성을 포함합니다.

  • Key
  • Timestamp
  • ConcurrencyCheck
  • Required
  • MinLength
  • MaxLength
  • StringLength

System.ComponentModel.DataAnnotations.Schema 네임 스페이스에는 데이터베이스의 스키마에 영향을주는 다음 속성이 포함됩니다.

  • Table
  • Column
  • Index
  • ForeignKey
  • NotMapped
  • InverseProperty

Entity Framework는 엔터티 추적에 사용하는 키 값이있는 모든 엔터티에 의존합니다. Code First가 의존하는 규칙 중 하나는 각 Code First 클래스에서 어떤 속성이 키인지를 의미하는 방법입니다.

  • 규칙은 "Id"라는 속성 또는 "StudentId"와 같이 클래스 이름과 "Id"를 결합한 속성을 찾는 것입니다.

  • 속성은 데이터베이스의 기본 키 열에 매핑됩니다.

  • 학생, 과정 및 등록 수업은이 규칙을 따릅니다.

이제 Student 클래스가 ID 대신 StdntID라는 이름을 사용했다고 가정 해 보겠습니다. Code First가이 규칙과 일치하는 속성을 찾지 못하면 키 속성이 있어야한다는 Entity Framework의 요구 사항 때문에 예외가 발생합니다. 키 주석을 사용하여 EntityKey로 사용할 속성을 지정할 수 있습니다.

StdntID를 포함하지만 기본 Code First 규칙을 따르지 않는 Student 클래스의 다음 코드를 살펴 보겠습니다. 따라서이를 처리하기 위해 키 속성이 추가되어 기본 키가됩니다.

public class Student {

   [Key]
   public int StdntID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

애플리케이션을 실행하고 SQL Server Explorer에서 데이터베이스를 살펴보면 이제 기본 키가 Students 테이블의 StdntID임을 알 수 있습니다.

Entity Framework는 복합 키도 지원합니다. Composite keys둘 이상의 속성으로 구성된 기본 키이기도합니다. 예를 들어 기본 키가 LicenseNumber 및 IssuingCountry의 조합 인 DrivingLicense 클래스가 있습니다.

public class DrivingLicense {

   [Key, Column(Order = 1)]
   public int LicenseNumber { get; set; }
   [Key, Column(Order = 2)]
   public string IssuingCountry { get; set; }
   public DateTime Issued { get; set; }
   public DateTime Expires { get; set; }
}

복합 키가있는 경우 Entity Framework에서는 키 속성의 순서를 정의해야합니다. 열 주석을 사용하여 순서를 지정할 수 있습니다.

타임 스탬프

Code First는 Timestamp 속성을 ConcurrencyCheck 속성과 동일하게 처리하지만 코드가 처음 생성하는 데이터베이스 필드가 null이 아닌지 확인합니다.

  • 동시성 확인을 위해 rowversion 또는 timestamp 필드를 사용하는 것이 더 일반적입니다.

  • ConcurrencyCheck 주석을 사용하는 대신 속성 유형이 바이트 배열 인 한보다 구체적인 TimeStamp 주석을 사용할 수 있습니다.

  • 주어진 클래스에는 하나의 타임 스탬프 속성 만있을 수 있습니다.

Course 클래스에 TimeStamp 속성을 추가하여 간단한 예를 살펴 보겠습니다.

public class Course {

   public int CourseID { get; set; }
   public string Title { get; set; }
   public int Credits { get; set; }
   [Timestamp]
   public byte[] TStamp { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

위의 예제에서 볼 수 있듯이 Timestamp 속성은 Course 클래스의 Byte [] 속성에 적용됩니다. 따라서 Code First는 TStampCourses 테이블에 타임 스탬프 열 을 생성 합니다.

동시성 검사

ConcurrencyCheck 주석을 사용하면 사용자가 항목을 편집하거나 삭제할 때 데이터베이스에서 동시성 검사에 사용할 하나 이상의 속성에 플래그를 지정할 수 있습니다. EF 디자이너로 작업 한 경우 속성의 ConcurrencyMode를 고정으로 설정하는 것과 일치합니다.

ConcurrencyCheck를 Course 클래스의 Title 속성에 추가하여 ConcurrencyCheck가 어떻게 작동하는지 간단한 예를 살펴 보겠습니다.

public class Course {

   public int CourseID { get; set; }
   [ConcurrencyCheck]
   public string Title { get; set; }
   public int Credits { get; set; }
   [Timestamp, DataType("timestamp")]
   public byte[] TimeStamp { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

위 과정 클래스에서 ConcurrencyCheck 속성은 기존 Title 속성에 적용됩니다. 이제 Code First는 다음 코드와 같이 낙관적 동시성을 확인하기 위해 update 명령에 Title 열을 포함합니다.

exec sp_executesql N'UPDATE [dbo].[Courses]
   SET [Title] = @0
   WHERE (([CourseID] = @1) AND ([Title] = @2))
   ',N'@0 nvarchar(max) ,@1 int,@2 nvarchar(max) ',@0=N'Maths',@1=1,@2=N'Calculus'
go

필수 주석

Required 주석은 특정 속성이 필요하다는 것을 EF에 알려줍니다. FirstMidName 속성에 Required id가 추가 된 다음 Student 클래스를 살펴 보겠습니다. 필수 특성은 EF가 속성에 데이터가 있는지 확인하도록합니다.

public class Student {

   [Key]
   public int StdntID { get; set; }

   [Required]
   public string LastName { get; set; }

   [Required]
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

위의 예에서 볼 수 있듯이 Required 속성은 FirstMidName 및 LastName에 적용됩니다. 따라서 Code First는 다음 이미지와 같이 Students 테이블에 NOT NULL FirstMidName 및 LastName 열을 만듭니다.

MaxLength

MaxLength 속성을 사용하면 추가 속성 유효성 검사를 지정할 수 있습니다. 도메인 클래스의 문자열 또는 배열 유형 속성에 적용 할 수 있습니다. EF Code First는 MaxLength 특성에 지정된대로 열의 크기를 설정합니다.

Title 속성에 MaxLength (24) 속성이 적용된 다음 Course 클래스를 살펴 보겠습니다.

public class Course {

   public int CourseID { get; set; }
   [ConcurrencyCheck]
   [MaxLength(24)]
   public string Title { get; set; }
   public int Credits { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

위의 응용 프로그램을 실행하면 Code First는 다음 이미지와 같이 CourseId 테이블에 nvarchar (24) 열 제목을 만듭니다.

사용자가 24자를 초과하는 제목을 설정하면 EF는 EntityValidationError를 발생시킵니다.

MinLength

MinLength 특성을 사용하면 MaxLength에서와 마찬가지로 추가 속성 유효성 검사를 지정할 수도 있습니다. MinLength 특성은 다음 코드와 같이 MaxLength 특성과 함께 사용할 수도 있습니다.

public class Course {

   public int CourseID { get; set; }
   [ConcurrencyCheck]
   [MaxLength(24) , MinLength(5)]
   public string Title { get; set; }
   public int Credits { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

MinLength 특성에 지정된 길이보다 작거나 MaxLength 특성에 지정된 길이보다 큰 Title 속성 값을 설정하면 EF에서 EntityValidationError가 발생합니다.

StringLength

StringLength를 사용하면 MaxLength와 같은 추가 속성 유효성 검사를 지정할 수도 있습니다. 유일한 차이점은 StringLength 특성은 Domain 클래스의 문자열 유형 속성에만 적용될 수 있다는 것입니다.

public class Course {

   public int CourseID { get; set; }
   [StringLength (24)]
   public string Title { get; set; }
   public int Credits { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

Entity Framework는 또한 StringLength 특성에 대한 속성 값의 유효성을 검사합니다. 사용자가 24자를 초과하는 제목을 설정하면 EF는 EntityValidationError를 발생시킵니다.

기본 Code First 규칙은 클래스 이름과 유사한 테이블 이름을 만듭니다. Code First가 데이터베이스를 생성하도록하고 생성중인 테이블의 이름도 변경하려는 경우. 그런 다음-

  • 기존 데이터베이스에서 Code First를 사용할 수 있습니다. 그러나 클래스 이름이 데이터베이스의 테이블 이름과 항상 일치하는 것은 아닙니다.

  • 테이블 속성은이 기본 규칙을 재정의합니다.

  • EF Code First는 주어진 도메인 클래스에 대해 Table 특성에 지정된 이름으로 테이블을 만듭니다.

클래스 이름이 Student이고 규칙에 따라 Code First는이 클래스가 Students라는 테이블에 매핑되는 것으로 가정하는 다음 예제를 살펴 보겠습니다. 그렇지 않은 경우 다음 코드와 같이 Table 속성을 사용하여 테이블 이름을 지정할 수 있습니다.

[Table("StudentsInfo")]
public class Student {

   [Key]
   public int StdntID { get; set; }
   [Required]
   public string LastName { get; set; }
   [Required]
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

이제 Table 속성이 테이블을 StudentsInfo로 지정하는 것을 볼 수 있습니다. 테이블이 생성되면 다음 이미지와 같이 테이블 이름 StudentsInfo가 표시됩니다.

테이블 이름을 지정할 수있을뿐만 아니라 다음 코드와 같이 Table 속성을 사용하여 테이블에 대한 스키마를 지정할 수도 있습니다.

[Table("StudentsInfo", Schema = "Admin")] 
public class Student {

   [Key]
   public int StdntID { get; set; }
   [Required]
   public string LastName { get; set; }
   [Required]
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

위의 예에서 테이블이 관리 스키마로 지정되었음을 알 수 있습니다. 이제 Code First는 다음 이미지와 같이 Admin 스키마에 StudentsInfo 테이블을 생성합니다.

기둥

또한 Table 속성과 동일하지만 Table 속성은 테이블 동작을 재정의하고 Column 속성은 열 동작을 재정의합니다. 기본 Code First 규칙은 속성 이름과 유사한 열 이름을 만듭니다. Code First가 데이터베이스를 생성하도록하고 테이블의 열 이름도 변경하려는 경우. 그런 다음-

  • 열 속성은 기본 규칙을 재정의합니다.

  • EF Code First는 지정된 속성의 열 특성에 지정된 이름으로 열을 만듭니다.

속성 이름이 FirstMidName이고 규칙에 따라 Code First는 이것이 FirstMidName이라는 열에 매핑되는 것으로 가정하는 다음 예제를 살펴 보겠습니다.

그렇지 않은 경우 다음 코드와 같이 Column 속성을 사용하여 열 이름을 지정할 수 있습니다.

public class Student {

   public int ID { get; set; }
   public string LastName { get; set; }
   [Column("FirstName")]
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

Column 속성이 열을 FirstName으로 지정하는 것을 볼 수 있습니다. 테이블이 생성되면 다음 이미지와 같이 열 이름 FirstName이 표시됩니다.

인덱스

Index 특성은 Entity Framework 6.1에서 도입되었습니다. 이전 버전을 사용하는 경우이 섹션의 정보가 적용되지 않습니다.

  • IndexAttribute를 사용하여 하나 이상의 열에 인덱스를 만들 수 있습니다.

  • 하나 이상의 속성에 특성을 추가하면 EF가 데이터베이스를 만들 때 데이터베이스에 해당 인덱스를 만듭니다.

  • 인덱스를 사용하면 대부분의 경우 데이터를 더 빠르고 효율적으로 검색 할 수 있습니다. 그러나 인덱스가있는 테이블 또는 뷰를 오버로드하면 삽입 또는 업데이트와 같은 다른 작업의 성능에 좋지 않은 영향을 미칠 수 있습니다.

  • 인덱싱은 데이터베이스에서 데이터를 쿼리하는 데 필요한 시간을 줄여 Code First 애플리케이션의 성능을 향상시킬 수있는 Entity Framework의 새로운 기능입니다.

  • Index 속성을 사용하여 데이터베이스에 인덱스를 추가하고 기본 고유 및 클러스터링 설정을 재정 의하여 시나리오에 가장 적합한 인덱스를 얻을 수 있습니다.

  • 기본적으로 인덱스 이름은 IX_ <property name>입니다.

학점에 대한 코스 클래스에 Index 속성이 추가 된 다음 코드를 살펴 보겠습니다.

public class Course {
   public int CourseID { get; set; }
   public string Title { get; set; }
   [Index]
   public int Credits { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

Index 속성이 Credits 속성에 적용된 것을 볼 수 있습니다. 테이블이 생성되면 인덱스에 IX_Credits가 표시됩니다.

기본적으로 색인은 고유하지 않지만 다음을 사용할 수 있습니다. IsUnique인덱스가 고유해야 함을 지정하는 명명 된 매개 변수입니다. 다음 예제는 다음 코드와 같이 고유 인덱스를 소개합니다.

public class Course {
   public int CourseID { get; set; }
   [Index(IsUnique = true)]
	
   public string Title { get; set; }
   [Index]
	
   public int Credits { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

ForeignKey

Code First 규칙은 모델에서 가장 일반적인 관계를 처리하지만 도움이 필요한 경우가 있습니다. 예를 들어 Student 클래스에서 키 속성의 이름을 변경하면 Enrollment 클래스와의 관계에 문제가 발생했습니다.

public class Enrollment {
   public int EnrollmentID { get; set; }
   public int CourseID { get; set; }
   public int StudentID { get; set; }
   public Grade? Grade { get; set; }
	
   public virtual Course Course { get; set; }
   public virtual Student Student { get; set; }
}

public class Student {
   [Key]
   public int StdntID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

데이터베이스를 생성하는 동안 Code First는 Enrollment 클래스의 StudentID 속성을보고 클래스 이름과 "ID"를 일치시키는 규칙에 따라 Student 클래스에 대한 외래 키로 인식합니다. 그러나 Student 클래스에는 StudentID 속성이 없지만 StdntID 속성은 Student 클래스입니다.

이에 대한 해결책은 Enrollment에서 탐색 속성을 만들고 ForeignKey DataAnnotation을 사용하여 Code First가 다음 코드와 같이 두 클래스 간의 관계를 구축하는 방법을 이해하는 데 도움을주는 것입니다.

public class Enrollment {
   public int EnrollmentID { get; set; }
   public int CourseID { get; set; }
   public int StudentID { get; set; }
	
   public Grade? Grade { get; set; }
   public virtual Course Course { get; set; }
   [ForeignKey("StudentID")]
	
   public virtual Student Student { get; set; }
}

이제 ForeignKey 특성이 탐색 속성에 적용되었음을 알 수 있습니다.

NotMapped

기본적으로 Code First 규칙에 따라 지원되는 데이터 유형이고 getter 및 setter를 포함하는 모든 속성이 데이터베이스에 표시됩니다. 그러나 이것은 귀하의 응용 프로그램에서 항상 그런 것은 아닙니다. NotMapped 속성은이 기본 규칙을 재정의합니다. 예를 들어, FatherName과 같은 Student 클래스에 속성이있을 수 있지만 저장할 필요는 없습니다. 다음 코드와 같이 데이터베이스에서 열을 생성하지 않으려는 FatherName 속성에 NotMapped 특성을 적용 할 수 있습니다.

public class Student {
   [Key]
   public int StdntID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
	
   public DateTime EnrollmentDate { get; set; }
   [NotMapped]

   public int FatherName { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

NotMapped 특성이 FatherName 속성에 적용된 것을 볼 수 있습니다. 테이블이 생성되면 FatherName 열은 데이터베이스에 생성되지 않지만 Student 클래스에는 존재합니다.

Code First는 Student 클래스의 Address 및 Age 속성에 대한 다음 예제와 같이 getter 또는 setter가없는 속성에 대한 열을 만들지 않습니다.

InverseProperty

InverseProperty는 클래스간에 여러 관계가있을 때 사용됩니다. 등록 클래스에서 현재 코스 및 이전 코스를 등록한 사람을 추적 할 수 있습니다. Enrollment 클래스에 대해 두 개의 탐색 속성을 추가해 보겠습니다.

public class Enrollment {
   public int EnrollmentID { get; set; }
   public int CourseID { get; set; }
   public int StudentID { get; set; }
   public Grade? Grade { get; set; }
	
   public virtual Course CurrCourse { get; set; }
   public virtual Course PrevCourse { get; set; }
   public virtual Student Student { get; set; }
}

마찬가지로 이러한 속성에서 참조하는 Course 클래스도 추가해야합니다. Course 클래스에는 현재 및 이전 등록을 모두 포함하는 Enrollment 클래스로 돌아가는 탐색 속성이 있습니다.

public class Course {

   public int CourseID { get; set; }
   public string Title { get; set; }
   [Index]

   public int Credits { get; set; }
   public virtual ICollection<Enrollment> CurrEnrollments { get; set; }
   public virtual ICollection<Enrollment> PrevEnrollments { get; set; }
}

Code First는 위 클래스와 같이 특정 클래스에 외래 키 속성이 포함되어 있지 않은 경우 {Class Name} _ {Primary Key} 외래 키 열을 생성합니다. 데이터베이스가 생성되면 다음과 같은 외래 키가 표시됩니다.

보시다시피 Code first는 자체적으로 두 클래스의 속성을 일치시킬 수 없습니다. 등록 용 데이터베이스 테이블에는 CurrCourse 용 외래 키 하나와 PrevCourse 용 외래 키 하나가 있어야하지만 Code First는 네 개의 외래 키 속성을 생성합니다.

  • CurrCourse _CourseID
  • PrevCourse _CourseID
  • Course_CourseID 및
  • Course_CourseID1

이러한 문제를 해결하려면 InverseProperty 주석을 사용하여 속성 정렬을 지정할 수 있습니다.

public class Course {

   public int CourseID { get; set; }
   public string Title { get; set; }
   [Index]

   public int Credits { get; set; }
   [InverseProperty("CurrCourse")]

   public virtual ICollection<Enrollment> CurrEnrollments { get; set; }
   [InverseProperty("PrevCourse")]

   public virtual ICollection<Enrollment> PrevEnrollments { get; set; }
}

보시다시피 InverseProperty 속성은 Enrollment 클래스의 참조 속성을 지정하여 위의 Course 클래스에 적용됩니다. 이제 Code First는 다음 이미지와 같이 데이터베이스를 생성하고 등록 테이블에 외래 키 열을 두 개만 만듭니다.

더 나은 이해를 위해 위의 예를 단계별로 실행하는 것이 좋습니다.

Fluent API는 데이터 주석으로 불가능한 일부 고급 구성 외에도 데이터 주석이 수행 할 수있는 모든 작업을 포함하는 모델 구성을 지정하는 고급 방법입니다. 데이터 주석과 유창한 API를 함께 사용할 수 있지만 Code First는 Fluent API> 데이터 주석> 기본 규칙에 우선 순위를 부여합니다.

  • Fluent API는 도메인 클래스를 구성하는 또 다른 방법입니다.

  • Code First Fluent API는 파생 된 DbContext에서 OnModelCreating 메서드를 재정 의하여 가장 일반적으로 액세스합니다.

  • Fluent API는 DataAnnotations보다 더 많은 구성 기능을 제공합니다. Fluent API는 다음 유형의 매핑을 지원합니다.

이 장에서는 다음 코드와 같이 Student, Course 및 Enrollment 클래스와 MyContext 이름이있는 컨텍스트 클래스가 포함 된 간단한 예제를 계속 진행합니다.

using System.Data.Entity; 
using System.Linq; 
using System.Text;
using System.Threading.Tasks;  

namespace EFCodeFirstDemo {

   class Program {
      static void Main(string[] args) {}
   }
   
   public enum Grade {
      A, B, C, D, F
   }

   public class Enrollment {
      public int EnrollmentID { get; set; }
      public int CourseID { get; set; }
      public int StudentID { get; set; }
      public Grade? Grade { get; set; }
		
      public virtual Course Course { get; set; }
      public virtual Student Student { get; set; }
   }

   public class Student {
      public int ID { get; set; }
      public string LastName { get; set; }
      public string FirstMidName { get; set; }
		
      public DateTime EnrollmentDate { get; set; }
		
      public virtual ICollection<Enrollment> Enrollments { get; set; }
   }

   public class Course {
      public int CourseID { get; set; }
      public string Title { get; set; }
      public int Credits { get; set; }
		
      public virtual ICollection<Enrollment> Enrollments { get; set; }
   }

   public class MyContext : DbContext {
      public virtual DbSet<Course> Courses { get; set; }
      public virtual DbSet<Enrollment> Enrollments { get; set; }
      public virtual DbSet<Student> Students { get; set; }
   }

}

Fluent API에 액세스하려면 DbContext에서 OnModelCreating 메서드를 재정의해야합니다. 다음 코드와 같이 student 테이블의 열 이름을 FirstMidName에서 FirstName으로 바꾸는 간단한 예제를 살펴 보겠습니다.

public class MyContext : DbContext {

   protected override void OnModelCreating(DbModelBuilder modelBuilder) {
      modelBuilder.Entity<Student>().Property(s ⇒ s.FirstMidName)
      .HasColumnName("FirstName");}

      public virtual DbSet<Course> Courses { get; set; }
      public virtual DbSet<Enrollment> Enrollments { get; set; }
      public virtual DbSet<Student> Students { get; set; }
}

DbModelBuilder는 CLR 클래스를 데이터베이스 스키마에 매핑하는 데 사용됩니다. 기본 클래스이며 모든 도메인 클래스를 구성 할 수 있습니다. EDM (엔터티 데이터 모델)을 빌드하는이 코드 중심 접근 방식을 Code First라고합니다.

Fluent API는 다양한 Code First 규칙을 재정의하기 위해 엔터티 및 해당 속성을 구성하는 여러 가지 중요한 메서드를 제공합니다. 아래는 그들 중 일부입니다.

Sr. No. 방법 이름 및 설명
1

ComplexType<TComplexType>

형식을 모델에 복합 형식으로 등록하고 복합 형식을 구성하는 데 사용할 수있는 개체를 반환합니다. 이 메서드는 여러 줄의 구성을 수행하기 위해 동일한 유형에 대해 여러 번 호출 할 수 있습니다.

2

Entity<TEntityType>

엔터티 형식을 모델의 일부로 등록하고 엔터티를 구성하는 데 사용할 수있는 개체를 반환합니다. 동일한 엔터티가 여러 줄의 구성을 수행하기 위해이 메서드를 여러 번 호출 할 수 있습니다.

HasKey<TKey>

이 엔터티 유형에 대한 기본 키 속성을 구성합니다.

4

HasMany<TTargetEntity>

이 엔티티 유형에서 많은 관계를 구성합니다.

5

HasOptional<TTargetEntity>

이 엔티티 유형에서 선택적 관계를 구성합니다. 엔티티 유형의 인스턴스는이 관계를 지정하지 않고도 데이터베이스에 저장할 수 있습니다. 데이터베이스의 외래 키는 Null을 허용합니다.

6

HasRequired<TTargetEntity>

이 엔터티 유형에서 필요한 관계를 구성합니다. 이 관계를 지정하지 않으면 엔티티 유형의 인스턴스를 데이터베이스에 저장할 수 없습니다. 데이터베이스의 외래 키는 null이 아닙니다.

7

Ignore<TProperty>

데이터베이스에 매핑되지 않도록 모델에서 속성을 제외합니다. (StructuralTypeConfiguration <TStructuralType>에서 상 속됨)

8

Property<T>

이 유형에 정의 된 구조체 속성을 구성합니다. (StructuralTypeConfiguration <TStructuralType>에서 상 속됨)

9

ToTable(String)

이 엔티티 유형이 매핑되는 테이블 이름을 구성합니다.

Fluent API를 사용하면 항목이 데이터베이스에 매핑되는 방식이나 서로 관련되는 방식에 대해 변경하려는 항목이나 해당 속성을 구성 할 수 있습니다. 구성을 사용하여 영향을 미칠 수있는 매우 다양한 매핑 및 모델링이 있습니다. 다음은 Fluent API가 지원하는 주요 매핑 유형입니다.

  • 엔티티 매핑
  • 속성 매핑

엔티티 매핑

엔터티 매핑은 클래스가 데이터베이스에 매핑되는 방식에 대한 Entity Framework의 이해에 영향을주는 몇 가지 간단한 매핑입니다. 이 모든 것들은 데이터 주석에서 논의되었으며 여기에서는 Fluent API를 사용하여 동일한 작업을 수행하는 방법을 살펴 보겠습니다.

  • 따라서 이러한 구성을 추가하기 위해 도메인 클래스로 이동하는 대신 컨텍스트 내에서이를 수행 할 수 있습니다.

  • 첫 번째는 onModelCreating 메서드를 재정 의하여 modelBuilder가 작업 할 수 있도록하는 것입니다.

기본 스키마

데이터베이스 생성시 기본 스키마는 dbo입니다. DbModelBuilder에서 HasDefaultSchema 메서드를 사용하여 모든 테이블, 저장 프로 시저 등에 사용할 데이터베이스 스키마를 지정할 수 있습니다.

관리 스키마가 적용된 다음 예제를 살펴 보겠습니다.

public class MyContext : DbContext {
   public MyContext() : base("name = MyContextDB") {}

   protected override void OnModelCreating(DbModelBuilder modelBuilder) {
      //Configure default schema
      modelBuilder.HasDefaultSchema("Admin");
   }
	
   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }
}

항목을 테이블에 매핑

기본 규칙에 따라 Code First는 코스, 등록 및 학생과 같은 컨텍스트 클래스에 DbSet 속성 이름으로 데이터베이스 테이블을 만듭니다. 그러나 다른 테이블 이름을 원하면이 규칙을 재정의하고 다음 코드에 표시된 것처럼 DbSet 속성과 다른 테이블 이름을 제공 할 수 있습니다.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   //Map entity to table
   modelBuilder.Entity<Student>().ToTable("StudentData");
   modelBuilder.Entity<Course>().ToTable("CourseDetail");
   modelBuilder.Entity<Enrollment>().ToTable("EnrollmentInfo");
}

데이터베이스가 생성되면 OnModelCreating 메서드에 지정된 테이블 이름이 표시됩니다.

엔티티 분할 (엔티티를 여러 테이블에 매핑)

항목 분할을 사용하면 여러 테이블에서 가져온 데이터를 단일 클래스로 결합 할 수 있으며 테이블간에 일대일 관계가있는 테이블에서만 사용할 수 있습니다. 학생 정보가 두 개의 테이블로 매핑되는 다음 예제를 살펴 보겠습니다.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {
   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   //Map entity to table
   modelBuilder.Entity<Student>().Map(sd ⇒ {
      sd.Properties(p ⇒ new { p.ID, p.FirstMidName, p.LastName });
      sd.ToTable("StudentData");
   })

   .Map(si ⇒ {
      si.Properties(p ⇒ new { p.ID, p.EnrollmentDate });
      si.ToTable("StudentEnrollmentInfo");
   });

   modelBuilder.Entity<Course>().ToTable("CourseDetail");
   modelBuilder.Entity<Enrollment>().ToTable("EnrollmentInfo");
}

위 코드에서는 Map 메서드를 사용하여 일부 속성을 StudentData 테이블에 매핑하고 일부 속성을 StudentEnrollmentInfo 테이블에 매핑하여 Student 엔터티가 다음 두 테이블로 분할 된 것을 볼 수 있습니다.

  • StudentData − 학생 FirstMidName 및 성을 포함합니다.

  • StudentEnrollmentInfo − EnrollmentDate를 포함합니다.

데이터베이스가 생성되면 다음 이미지에 표시된대로 데이터베이스에 다음 테이블이 표시됩니다.

속성 매핑

Property 메서드는 엔터티 또는 복합 유형에 속하는 각 속성에 대한 특성을 구성하는 데 사용됩니다. Property 메서드는 지정된 속성에 대한 구성 개체를 가져 오는 데 사용됩니다. Fluent API를 사용하여 도메인 클래스의 속성을 매핑하고 구성 할 수도 있습니다.

기본 키 구성

기본 키의 기본 규칙은 다음과 같습니다.

  • 클래스는 이름이 "ID"또는 "Id"인 속성을 정의합니다.
  • 클래스 이름 뒤에 "ID"또는 "ID"가 표시됨

학생 클래스의 다음 코드에 표시된대로 클래스가 기본 키에 대한 기본 규칙을 따르지 않는 경우-

public class Student {
   public int StdntID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

그런 다음 속성을 기본 키로 명시 적으로 설정하려면 다음 코드와 같이 HasKey 메서드를 사용할 수 있습니다.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {
   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");
	
   // Configure Primary Key
   modelBuilder.Entity<Student>().HasKey<int>(s ⇒ s.StdntID); 
}

열 구성

Entity Framework에서 기본적으로 Code First는 동일한 이름, 순서 및 데이터 형식을 가진 속성에 대한 열을 만듭니다. 그러나 다음 코드와 같이이 규칙을 재정의 할 수도 있습니다.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   //Configure EnrollmentDate Column
   modelBuilder.Entity<Student>().Property(p ⇒ p.EnrollmentDate)
	
   .HasColumnName("EnDate")
   .HasColumnType("DateTime")
   .HasColumnOrder(2);
}

MaxLength 속성 구성

다음 예에서 과정 제목 속성은 24 자 이하이어야합니다. 사용자가 24 자보다 긴 값을 지정하면 사용자에게 DbEntityValidationException 예외가 발생합니다.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {
   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");
   modelBuilder.Entity<Course>().Property(p ⇒ p.Title).HasMaxLength(24);
}

Null 또는 NotNull 속성 구성

다음 예제에서는 과정 제목 속성이 필요하므로 IsRequired 메서드를 사용하여 NotNull 열을 만듭니다. 마찬가지로 Student EnrollmentDate는 선택 사항이므로 IsOptional 메서드를 사용하여 다음 코드와 같이이 열에 null 값을 허용합니다.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");
   modelBuilder.Entity<Course>().Property(p ⇒ p.Title).IsRequired();
   modelBuilder.Entity<Student>().Property(p ⇒ p.EnrollmentDate).IsOptional();
	
   //modelBuilder.Entity<Student>().Property(s ⇒ s.FirstMidName)
   //.HasColumnName("FirstName"); 
}

관계 구성

데이터베이스 컨텍스트에서 관계는 한 테이블에 다른 테이블의 기본 키를 참조하는 외래 키가있을 때 두 관계형 데이터베이스 테이블 사이에 존재하는 상황입니다. Code First로 작업 할 때 도메인 CLR 클래스를 정의하여 모델을 정의합니다. 기본적으로 Entity Framework는 Code First 규칙을 사용하여 클래스를 데이터베이스 스키마에 매핑합니다.

  • Code First 명명 규칙을 사용하는 경우 대부분의 경우 Code First를 사용하여 외래 키 및 탐색 속성을 기반으로 테이블 간의 관계를 설정할 수 있습니다.

  • 이러한 규칙을 충족하지 못하는 경우 클래스 간의 관계에 영향을주고 Code First에서 구성을 추가 할 때 이러한 관계가 데이터베이스에서 실현되는 방식에 영향을주는 구성도 있습니다.

  • 이들 중 일부는 데이터 주석에서 사용할 수 있으며 Fluent API를 사용하여 더 복잡한 일부를 적용 할 수 있습니다.

일대일 관계 구성

모델에서 일대일 관계를 정의 할 때 각 클래스에서 참조 탐색 속성을 사용합니다. 데이터베이스에서 두 테이블은 관계의 양쪽에 하나의 레코드 만 가질 수 있습니다. 각 기본 키 값은 관련 테이블에있는 하나의 레코드 (또는 레코드 없음)에만 관련됩니다.

  • 관련 열이 모두 기본 키이거나 고유 한 제약 조건이있는 경우 일대일 관계가 생성됩니다.

  • 일대일 관계에서 기본 키는 추가로 외래 키 역할을하며 두 테이블에 대해 별도의 외래 키 열이 없습니다.

  • 이러한 방식으로 관련된 대부분의 정보가 모두 하나의 테이블에 있기 때문에 이러한 유형의 관계는 일반적이지 않습니다.

일대일 관계를 만들기 위해 모델에 다른 클래스를 추가하는 다음 예제를 살펴 보겠습니다.

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual StudentLogIn StudentLogIn { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

public class StudentLogIn {
   [Key, ForeignKey("Student")]
   public int ID { get; set; }
   public string EmailID { get; set; }
   public string Password { get; set; }
	
   public virtual Student Student { get; set; }
}

위의 코드에서 볼 수 있듯이 StudentLogIn 클래스의 ID 속성에는 Key 및 ForeignKey 속성이 사용되어 Primary Key와 Foreign Key로 표시됩니다.

Fluent API를 사용하여 Student와 StudentLogIn 간의 1 대 0 또는 하나의 관계를 구성하려면 다음 코드와 같이 OnModelCreating 메서드를 재정의해야합니다.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   // Configure ID as PK for StudentLogIn
   modelBuilder.Entity<StudentLogIn>()
   .HasKey(s ⇒ s.ID);

   // Configure ID as FK for StudentLogIn
   modelBuilder.Entity<Student>()
   
   .HasOptional(s ⇒ s.StudentLogIn) //StudentLogIn is optional
   .WithRequired(t ⇒ t.Student); // Create inverse relationship
}

대부분의 경우 Entity Framework는 관계에서 어떤 유형이 종속이고 어떤 유형이 주체인지 추론 할 수 있습니다. 그러나 관계의 양쪽 끝이 모두 필요하거나 양쪽이 선택 사항 인 경우 Entity Framework는 종속 항목과 주체를 식별 할 수 없습니다. 관계의 양쪽 끝이 모두 필요한 경우 다음 코드와 같이 HasRequired를 사용할 수 있습니다.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   // Configure ID as PK for StudentLogIn
   modelBuilder.Entity<StudentLogIn>()
   .HasKey(s ⇒ s.ID);

   // Configure ID as FK for StudentLogIn
   modelBuilder.Entity<Student>()
   .HasRequired(r ⇒ r.Student)
   .WithOptional(s ⇒ s.StudentLogIn);  
}

데이터베이스가 생성되면 다음 이미지와 같이 관계가 생성되는 것을 볼 수 있습니다.

일대 다 관계 구성

기본 키 테이블에는 관련 테이블의 없음, 하나 또는 많은 레코드와 관련된 하나의 레코드 만 포함됩니다. 이것은 가장 일반적으로 사용되는 관계 유형입니다.

  • 이 유형의 관계에서 테이블 A의 행은 테이블 B에서 일치하는 행을 많이 가질 수 있지만 테이블 B의 행은 테이블 A에서 일치하는 행을 하나만 가질 수 있습니다.

  • 외래 키는 관계의 많은 끝을 나타내는 테이블에 정의됩니다.

  • 예를 들어, 위의 다이어그램에서 Student 및 Enrollment 테이블에는 일대일 관계가 있고 각 학생은 여러 등록을 가질 수 있지만 각 등록은 한 학생에만 속합니다.

아래는 일대 다 관계가있는 학생 및 등록이지만 등록 테이블의 외래 키가 기본 코드 우선 규칙을 따르지 않습니다.

public class Enrollment {
   public int EnrollmentID { get; set; }
   public int CourseID { get; set; }
	
   //StdntID is not following code first conventions name
   public int StdntID { get; set; }
   public Grade? Grade { get; set; }
	
   public virtual Course Course { get; set; }
   public virtual Student Student { get; set; }
}

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual StudentLogIn StudentLogIn { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

이 경우 Fluent API를 사용하여 일대 다 관계를 구성하려면 다음 코드와 같이 HasForeignKey 메서드를 사용해야합니다.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   //Configure FK for one-to-many relationship
   modelBuilder.Entity<Enrollment>()

   .HasRequired<Student>(s ⇒ s.Student)
   .WithMany(t ⇒ t.Enrollments)
   .HasForeignKey(u ⇒ u.StdntID);  
}

데이터베이스가 생성되면 다음 이미지와 같이 관계가 생성 된 것을 볼 수 있습니다.

위의 예제에서 HasRequired 메서드는 Student 탐색 속성이 Null이어야 함을 지정합니다. 따라서 Enrollment를 추가하거나 업데이트 할 때마다 Student with Enrollment 엔터티를 할당해야합니다. 이를 처리하려면 HasRequired 메서드 대신 HasOptional 메서드를 사용해야합니다.

다 대다 관계 구성

두 테이블의 각 레코드는 다른 테이블의 레코드 수에 관계없이 (또는 레코드 없음) 관련 될 수 있습니다.

  • 정션 테이블이라는 세 번째 테이블을 정의하여 이러한 관계를 만들 수 있습니다.이 테이블의 기본 키는 테이블 A와 테이블 B의 외래 키로 구성됩니다.

  • 예를 들어, Student 테이블과 Course 테이블에는 다 대다 관계가 있습니다.

다음은 Student 및 Course가 다 토모 관계를 갖는 Student 및 Course 클래스입니다. 두 클래스 모두 탐색 속성 인 Students 및 Courses가 컬렉션이기 때문입니다. 즉, 한 엔터티에 다른 엔터티 컬렉션이 있습니다.

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Course> Courses { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

public class Course {
   public int CourseID { get; set; }
   public string Title { get; set; }
   public int Credits { get; set; }
	
   public virtual ICollection<Student> Students { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

Student와 Course 사이에 다 대다 관계를 구성하려면 다음 코드와 같이 Fluent API를 사용할 수 있습니다.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   // Configure many-to-many relationship
   modelBuilder.Entity<Student>()
   .HasMany(s ⇒ s.Courses) 
   .WithMany(s ⇒ s.Students);
}

기본 Code First 규칙은 데이터베이스가 생성 될 때 조인 테이블을 만드는 데 사용됩니다. 결과적으로 다음 이미지와 같이 Course_CourseID 및 Student_ID 열이있는 StudentCourses 테이블이 생성됩니다.

조인 테이블 이름과 테이블의 열 이름을 지정하려면 Map 메서드를 사용하여 추가 구성을 수행해야합니다.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   // Configure many-to-many relationship 
   modelBuilder.Entity<Student>()

   .HasMany(s ⇒ s.Courses)
   .WithMany(s ⇒ s.Students)
   
   .Map(m ⇒ {
      m.ToTable("StudentCoursesTable");
      m.MapLeftKey("StudentID");
      m.MapRightKey("CourseID");
   }); 
}

데이터베이스 생성 시점을 알 수 있으며, 위 코드에서 지정한대로 테이블과 컬럼 이름이 생성됩니다.

더 나은 이해를 위해 위의 예를 단계별로 실행하는 것이 좋습니다.

Entity Framework에서 Seed는 EF 4.1에 도입되었으며 데이터베이스 이니셜 라이저와 함께 작동합니다. 일반적인 아이디어Seed MethodCode First에 의해 생성되거나 마이그레이션에 의해 발전된 데이터베이스로 데이터를 초기화하는 것입니다. 이 데이터는 종종 테스트 데이터이지만 알려진 학생, 코스 등의 목록과 같은 참조 데이터 일 수도 있습니다. 데이터가 초기화되면 다음을 수행합니다.

  • 대상 데이터베이스가 이미 존재하는지 확인합니다.
  • 그렇다면 현재 Code First 모델은 데이터베이스의 메타 데이터에 저장된 모델과 비교됩니다.
  • 현재 모델이 데이터베이스의 모델과 일치하지 않으면 데이터베이스가 삭제됩니다.
  • 데이터베이스가 삭제되었거나 처음에 존재하지 않은 경우 생성됩니다.
  • 데이터베이스가 생성 된 경우 이니셜 라이저 Seed 메서드가 호출됩니다.

Seed 메서드는 데이터베이스 컨텍스트 개체를 입력 매개 변수로 사용하고 메서드의 코드는 해당 개체를 사용하여 데이터베이스에 새 엔터티를 추가합니다. 데이터베이스에 데이터를 시드하려면 Seed 메서드를 재정의해야합니다. 일부 기본 데이터가 내부 클래스의 데이터베이스로 시작되는 다음 예제를 살펴 보겠습니다.

private class UniDBInitializer<T> : DropCreateDatabaseAlways<MyContext> {

   protected override void Seed(MyContext context) {

      IList<Student> students = new List<Student>();

      students.Add(new Student() {
         FirstMidName = "Andrew", 
         LastName = "Peters", 
         EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
      });

      students.Add(new Student() {
         FirstMidName = "Brice", 
         LastName = "Lambson", 
         EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
      });

      students.Add(new Student() {
         FirstMidName = "Rowan", 
         LastName = "Miller", 
         EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
      });

      foreach (Student student in students)
      context.Students.Add(student);
      base.Seed(context);
   }
}

위 코드에서는 student 테이블이 초기화됩니다. 다음 코드와 같이 컨텍스트 클래스에서이 DB 이니셜 라이저 클래스를 설정해야합니다.

public MyContext() : base("name=MyContextDB") {
   Database.SetInitializer<MyContext>(new UniDBInitializer<MyContext>());
}

다음은 DB 이니셜 라이저 클래스도 포함하는 MyContext 클래스의 전체 클래스 구현입니다.

public class MyContext : DbContext {

   public MyContext() : base("name=MyContextDB") {
      Database.SetInitializer<MyContext>(new UniDBInitializer<MyContext>());
   }

   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }
	
   private class UniDBInitializer<T> : DropCreateDatabaseAlways<MyContext> {

      protected override void Seed(MyContext context) {

         IList<Student> students = new List<Student>();
			
         students.Add(new Student() {
            FirstMidName = "Andrew", 
            LastName = "Peters", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString()) 
         });

         students.Add(new Student() {
            FirstMidName = "Brice", 
            LastName = "Lambson", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
         });

         students.Add(new Student() {
            FirstMidName = "Rowan", 
            LastName = "Miller", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
         });

         foreach (Student student in students)
         context.Students.Add(student);
         base.Seed(context);
      }
   } 
}

위 예제를 컴파일하고 실행하면 다음 이미지와 같이 데이터베이스의 데이터를 볼 수 있습니다.

더 나은 이해를 위해 위의 예를 단계별로 실행하는 것이 좋습니다.

Entity Framework 4.3에는 시간이 지남에 따라 모델이 변경됨에 따라 데이터베이스 스키마를 점진적으로 발전시킬 수있는 새로운 Code First 마이그레이션 기능이 포함되어 있습니다. 대부분의 개발자에게 이것은 데이터베이스를 수동으로 업데이트하거나 모델이 변경 될 때이를 삭제하고 다시 만들어야하는 4.1 및 4.2 릴리스의 데이터베이스 이니셜 라이저 옵션에 비해 크게 향상되었습니다.

  • Entity Framework 4.3 이전에는 데이터베이스에 이미 데이터 (시드 데이터 제외) 또는 기존 저장 프로 시저, 트리거 등이있는 경우 이러한 전략이 전체 데이터베이스를 삭제하고 다시 만드는 데 사용되었으므로 데이터 및 기타 DB를 잃게됩니다. 사물.

  • 마이그레이션을 통해 기존 데이터 또는 기타 데이터베이스 개체를 잃지 않고 모델이 변경 될 때 데이터베이스 스키마를 자동으로 업데이트합니다.

  • MigrateDatabaseToLatestVersion이라는 새 데이터베이스 이니셜 라이저를 사용합니다.

마이그레이션에는 두 종류가 있습니다-

  • 자동화 된 마이그레이션
  • 코드 기반 마이그레이션

자동화 된 마이그레이션

자동 마이그레이션은 Entity Framework 4.3에서 처음 도입되었습니다. 자동 마이그레이션에서는 코드 파일에서 데이터베이스 마이그레이션을 수동으로 처리 할 필요가 없습니다. 예를 들어 각 변경에 대해 도메인 클래스도 변경해야합니다. 그러나 자동화 된 마이그레이션을 사용하려면 패키지 관리자 콘솔에서 명령을 실행하기 만하면됩니다.

자동화 된 마이그레이션의 다음 단계별 프로세스를 살펴 보겠습니다.

Code First 접근 방식을 사용하면 애플리케이션을위한 데이터베이스가 없습니다.

이 예에서는 다음 코드와 같이 Student, Course 및 Enrollment와 같은 세 가지 기본 클래스로 시작합니다.

public class Enrollment {
   public int EnrollmentID { get; set; }
   public int CourseID { get; set; }
   public int StudentID { get; set; }
   public Grade? Grade { get; set; }
	
   public virtual Course Course { get; set; }
   public virtual Student Student { get; set; }

}

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }

}

public class Course {
   public int CourseID { get; set; }
   public string Title { get; set; }
   [Index]
   public int Credits { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }

}

다음은 컨텍스트 클래스입니다.

public class MyContext : DbContext {
   public MyContext() : base("MyContextDB") {}
   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }
}

애플리케이션을 실행하기 전에 자동 마이그레이션을 활성화해야합니다.

Step 1 − 도구 → NuGet 패키지 관리자 → 패키지 관리자 콘솔에서 패키지 관리자 콘솔을 엽니 다.

Step 2 − 자동 마이그레이션을 활성화하려면 패키지 관리자 콘솔에서 다음 명령을 실행하십시오.

PM> enable-migrations -EnableAutomaticMigrations:$true

Step 3 − 명령이 성공적으로 실행되면 다음 코드와 같이 프로젝트의 Migration 폴더에 내부 봉인 된 구성 클래스를 생성합니다.

namespace EFCodeFirstDemo.Migrations {

   using System;
   using System.Data.Entity;
   using System.Data.Entity.Migrations;
   using System.Linq;
	
   internal sealed class Configuration : DbMigrationsConfiguration<EFCodeFirstDemo.MyContext> {

      public Configuration() {
         AutomaticMigrationsEnabled = true;
         ContextKey = "EFCodeFirstDemo.MyContext";
      }

      protected override void Seed(EFCodeFirstDemo.MyContext context) {

         //  This method will be called after migrating to the latest version.
         //  You can use the DbSet<T>.AddOrUpdate() helper extension method
         //  to avoid creating duplicate seed data. E.g.

         //  context.People.AddOrUpdate(
            //  p ⇒ p.FullName, 
            //  new Person { FullName = "Andrew Peters" }, 
            //  new Person { FullName = "Brice Lambson" }, 
            //  new Person { FullName = "Rowan Miller" }
         //  );
      }
   }
}

Step 4 − 새로운 DB 초기화 전략 MigrateDatabaseToLatestVersion을 사용하여 컨텍스트 클래스에서 데이터베이스 초기화 프로그램을 설정합니다.

public class MyContext : DbContext {

   public MyContext() : base("MyContextDB") {
      Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, 
         EFCodeFirstDemo.Migrations.Configuration>("MyContextDB"));
   }

   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }

}

Step 5− 자동 마이그레이션을 설정했습니다. 애플리케이션을 실행하면 모델을 변경할 때 자동으로 마이그레이션을 처리합니다.

Step 6− 보시다시피 하나의 시스템 테이블 __MigrationHistory는 다른 테이블과 함께 데이터베이스에도 생성됩니다. __MigrationHistory에서 자동 마이그레이션은 데이터베이스 변경 내역을 유지합니다.

Step 7− 도메인 클래스로 다른 엔티티 클래스를 추가하고 애플리케이션을 실행하면 데이터베이스에 테이블이 생성됩니다. 다음 StudentLogIn 클래스를 추가해 보겠습니다.

public class StudentLogIn {
   [Key, ForeignKey("Student")]
   public int ID { get; set; }
   public string EmailID { get; set; }
   public string Password { get; set; }
	
   public virtual Student Student { get; set; }
}

Step 8 − 다음 코드와 같이 컨텍스트 클래스에 위에서 언급 한 클래스에 대한 DBSet을 추가하는 것을 잊지 마십시오.

public virtual DbSet<StudentLogIn> StudentsLogIn { get; set; }

Step 9 − 애플리케이션을 다시 실행하면 StudentsLogIn 테이블이 데이터베이스에 추가 된 것을 볼 수 있습니다.

자동화 된 마이그레이션에 대해 언급 된 위의 단계는 엔터티에서만 작동합니다. 예를 들어 다른 엔티티 클래스를 추가하거나 기존 엔티티 클래스를 제거하려면 성공적으로 마이그레이션됩니다. 그러나 엔티티 클래스에 속성을 추가하거나 제거하면 예외가 발생합니다.

Step 10 − 속성 마이그레이션을 처리하려면 구성 클래스 생성자에서 AutomaticMigrationDataLossAllowed = true를 설정해야합니다.

public Configuration() {
   AutomaticMigrationsEnabled = true;
   AutomaticMigrationDataLossAllowed = true;
   ContextKey = "EFCodeFirstDemo.MyContext";
}

코드 기반 마이그레이션

새 애플리케이션을 개발하면 데이터 모델이 자주 변경되며 모델이 변경 될 때마다 데이터베이스와 동기화되지 않습니다. 데이터 모델을 변경할 때마다 데이터베이스를 자동으로 삭제하고 다시 만들도록 Entity Framework를 구성했습니다. 코드 기반 마이그레이션은 마이그레이션에 대한 더 많은 제어를 원할 때 유용합니다.

  • 엔터티 클래스를 추가, 제거 또는 변경하거나 DbContext 클래스를 변경하면 다음에 애플리케이션을 실행할 때 기존 데이터베이스가 자동으로 삭제되고 모델과 일치하는 새 데이터베이스가 생성되며 테스트 데이터로 시드됩니다.

  • Code First 마이그레이션 기능은 Code First가 데이터베이스를 삭제하고 다시 만드는 대신 데이터베이스 스키마를 업데이트 할 수 있도록하여이 문제를 해결합니다. 애플리케이션을 배포하려면 마이그레이션을 활성화해야합니다.

다음은 데이터베이스의 변경 사항을 마이그레이션하는 기본 규칙입니다.

  • 마이그레이션 활성화
  • 마이그레이션 추가
  • 데이터베이스 업데이트

코드 기반 마이그레이션의 다음 단계별 프로세스를 살펴 보겠습니다.

코드 우선 접근 방식을 사용하면 애플리케이션에 대한 데이터베이스가 없습니다.

이 예에서는 다음 코드에 표시된대로 Student, Course 및 Enrollment와 같은 3 가지 기본 클래스로 다시 시작합니다.

public class Enrollment {
   public int EnrollmentID { get; set; }
   public int CourseID { get; set; }
   public int StudentID { get; set; }
   public Grade? Grade { get; set; }
	
   public virtual Course Course { get; set; }
   public virtual Student Student { get; set; }

}

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }

}

public class Course {
   public int CourseID { get; set; }
   public string Title { get; set; }
   [Index]
   public int Credits { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }

}

다음은 컨텍스트 클래스입니다.

public class MyContext : DbContext {

   public MyContext() : base("MyContextDB") {
      Database.SetInitializer(new MigrateDatabaseToLatestVersion<
         MyContext, EFCodeFirstDemo.Migrations.Configuration>("MyContextDB"));
   }

   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }

}

Step 1 − 애플리케이션을 실행하기 전에 마이그레이션을 활성화해야합니다.

Step 2 − 도구 → NuGet 패키지 관리자 → 패키지 관리자 콘솔에서 패키지 관리자 콘솔을 엽니 다.

Step 3 − 마이그레이션이 이미 활성화되어 있습니다. 이제 다음 명령을 실행하여 애플리케이션에 마이그레이션을 추가하십시오.

PM> add-migration "UniDB Schema"

Step 4 − 명령이 성공적으로 실행되면 다음 이미지와 같이 타임 스탬프 접두사를 사용하여 명령에 전달한 매개 변수 이름으로 마이그레이션 폴더에 새 파일이 생성 된 것을 볼 수 있습니다.

Step 5 − "update-database"명령을 사용하여 데이터베이스를 생성하거나 업데이트 할 수 있습니다.

PM> Update-Database -Verbose

"-Verbose"플래그는 콘솔의 대상 데이터베이스에 적용되는 SQL 문을 표시하도록 지정합니다.

Step 6 − 학생 클래스에 'Age'속성을 하나 더 추가 한 다음 update 문을 실행 해 보겠습니다.

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public int Age { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }

}

PM → Update-Database –Verbose를 실행하면 명령이 성공적으로 실행되면 새 열 Age가 데이터베이스에 추가 된 것을 볼 수 있습니다.

더 나은 이해를 위해 위의 예를 단계별로 실행하는 것이 좋습니다.

이 장에서는 응용 프로그램에 여러 DbContext 클래스가있을 때 변경 사항을 데이터베이스로 마이그레이션하는 방법을 배웁니다.

  • 다중 DbContext는 Entity Framework 6.0에서 처음 도입되었습니다.
  • 여러 컨텍스트 클래스는 단일 데이터베이스 또는 두 개의 다른 데이터베이스에 속할 수 있습니다.

이 예에서는 동일한 데이터베이스에 대해 두 개의 Context 클래스를 정의합니다. 다음 코드에는 Student 및 Teacher에 대한 두 개의 DbContext 클래스가 있습니다.

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
}

public class MyStudentContext : DbContext {
   public MyStudentContext() : base("UniContextDB") {}
   public virtual DbSet<Student> Students { get; set; }
}

public class Teacher {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime HireDate { get; set; }
}

public class MyTeacherContext : DbContext {
   public MyTeacherContext() : base("UniContextDB") {}
   public virtual DbSet<Teacher> Teachers { get; set; }
}

위 코드에서 볼 수 있듯이“Student”와“Teacher”라는 두 가지 모델이 있습니다. 각각은 특정 해당 컨텍스트 클래스와 연관됩니다. 즉, Student는 MyStudentContext와 연관되고 Teacher는 MyTeacherContext와 연관됩니다.

다음은 동일한 프로젝트 내에 여러 컨텍스트 클래스가있을 때 데이터베이스의 변경 사항을 마이그레이션하는 기본 규칙입니다.

  • enable-migrations -ContextTypeName <DbContext-Name-with-Namespaces> MigrationsDirectory : <Migrations-Directory-Name>

  • Add-Migration -configuration <DbContext-Migrations-Configuration-Class-withNamespaces> <Migrations-Name>

  • Update-Database -configuration <DbContext-Migrations-Configuration-Class-withNamespaces> -Verbose

패키지 관리자 콘솔에서 다음 명령을 실행하여 MyStudentContext에 대한 마이그레이션을 활성화하겠습니다.

PM→ enable-migrations -ContextTypeName:EFCodeFirstDemo.MyStudentContext

일단 실행되면 마이그레이션 내역에 모델을 추가하고이를 위해 동일한 콘솔에서 add-migration 명령을 실행해야합니다.

PM→ add-migration -configuration EFCodeFirstDemo.Migrations.Configuration Initial

이제 데이터베이스의 Students 및 Teachers 테이블에 데이터를 추가해 보겠습니다.

static void Main(string[] args) {

   using (var context = new MyStudentContext()) {
	
      //// Create and save a new Students
      Console.WriteLine("Adding new students");

      var student = new Student {
         FirstMidName = "Alain", 
         LastName = "Bomer", 
         EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
         //Age = 24
      };

      context.Students.Add(student);

      var student1 = new Student {
         FirstMidName = "Mark",
         LastName = "Upston", 
         EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
         //Age = 30
      };

      context.Students.Add(student1);
      context.SaveChanges();
      // Display all Students from the database
      var students = (from s in context.Students orderby s.FirstMidName
         select s).ToList<Student>();
		
      Console.WriteLine("Retrieve all Students from the database:");

      foreach (var stdnt in students) {
         string name = stdnt.FirstMidName + " " + stdnt.LastName;
         Console.WriteLine("ID: {0}, Name: {1}", stdnt.ID, name);
      }

      Console.WriteLine("Press any key to exit...");
      Console.ReadKey();
   }

   using (var context = new MyTeacherContext()) {

      //// Create and save a new Teachers
      Console.WriteLine("Adding new teachers");

      var student = new Teacher {
         FirstMidName = "Alain", 
         LastName = "Bomer", 
         HireDate = DateTime.Parse(DateTime.Today.ToString())
         //Age = 24
      };

      context.Teachers.Add(student);

      var student1 = new Teacher {
         FirstMidName = "Mark", 
         LastName = "Upston", 
         HireDate = DateTime.Parse(DateTime.Today.ToString())
         //Age = 30
      };

      context.Teachers.Add(student1);
      context.SaveChanges();
  
      // Display all Teachers from the database
      var teachers = (from t in context.Teachers orderby t.FirstMidName
         select t).ToList<Teacher>();
		
      Console.WriteLine("Retrieve all teachers from the database:");

      foreach (var teacher in teachers) {
         string name = teacher.FirstMidName + " " + teacher.LastName;
         Console.WriteLine("ID: {0}, Name: {1}", teacher.ID, name);
      }

      Console.WriteLine("Press any key to exit...");
      Console.ReadKey();
   }
}

위의 코드가 실행되면 다음 이미지와 같이 두 개의 다른 모델에 대해 두 개의 다른 테이블이 생성되는 것을 볼 수 있습니다.

더 나은 이해를 위해 위의 예를 단계별로 실행하는 것이 좋습니다.

Entity Framework 6 이전에는 Entity Framework가 다른 엔터티 또는 복합 형식 내에 중첩 된 엔터티 또는 복합 형식을 인식하지 못했습니다. Entity Framework가 모델을 생성 할 때 중첩 된 형식이 사라졌습니다.

세 개의 엔터티 Student, Course 및 Enrollment가있는 기본 모델이있는 간단한 예제를 살펴 보겠습니다.

  • Person 유형 인 Identity 속성을 추가해 보겠습니다. Person은 BirthDate 및 FatherName 속성을 포함하는 다른 엔터티입니다.

  • Entity Framework 용어로는 ID가없고 엔터티의 일부이기 때문에 Entity Framework 복합 유형이며 실제로 Entity Framework의 첫 번째 버전부터 복합 유형을 지원했습니다.

  • Person 유형은 다음 코드와 같이 중첩되지 않습니다.

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
   public Person Identity { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

public class Person {

   public Person(string fatherName, DateTime birthDate) {
      FatherName = fatherName;
      BirthDate = birthDate;
   }
	
   public string FatherName { get; set; }
   public DateTime BirthDate { get; set; }
}

Entity Framework는 이전 버전에서도 사용되는 경우 Person 형식을 유지하는 방법을 알고 있습니다.

Entity Framework Power Tool을 사용하면 Entity Framework가 모델을 해석하는 방법을 볼 수 있습니다. Program.cs 파일을 마우스 오른쪽 버튼으로 클릭하고 Entity Framework → 엔티티 데이터 모델보기 (읽기 전용)를 선택합니다.

이제 Identity 속성이 Student 클래스에 정의되어 있음을 알 수 있습니다.

이 Person 클래스를 다른 엔터티에서 사용하지 않는 경우 Student 클래스 내에 중첩 할 수 있지만이 이전 버전의 Entity Framework는 중첩 된 형식을 인식하지 않습니다.

이전 버전에서는 모델을 다시 생성합니다. 유형이 인식되지 않을뿐만 아니라 속성이 없기 때문에 속성도 존재하지 않으므로 Entity Framework는 Person 유형을 전혀 유지하지 않습니다.

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
	
   public DateTime EnrollmentDate { get; set; }
   public Person Identity { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }

   public class Person {

      public Person(string fatherName, DateTime birthDate) {
         FatherName = fatherName;
         BirthDate = birthDate;
      }

      public string FatherName { get; set; }
      public DateTime BirthDate { get; set; }
   }
}

Entity Framework 6에서는 중첩 된 엔터티와 복합 형식이 인식됩니다. 위의 코드에서 Person이 Student 클래스 내에 중첩되어 있음을 알 수 있습니다.

이번에는 Entity Framework Power Tool을 사용하여 Entity Framework가 모델을 해석하는 방법을 보여줄 때 진정한 Identity 속성과 Person 복합 유형이 있습니다. 따라서 Entity Framework는 해당 데이터를 유지합니다.

이제 Identity가 Entity Framework 6 이전에 지원되지 않았던 중첩 된 엔터티 유형임을 알 수 있습니다.

더 나은 이해를 위해 위의 예를 단계별로 실행하는 것이 좋습니다.