다음을 통해 공유


Code First 삽입, 업데이트 및 삭제 저장 프로시저

참고 항목

EF6 이상만 - 이 페이지에서 다루는 기능, API 등은 Entity Framework 6에 도입되었습니다. 이전 버전을 사용하는 경우 이 정보의 일부 또는 전체가 적용되지 않습니다.

기본적으로 Code First는 직접 테이블 액세스를 사용하여 삽입, 업데이트 및 삭제 명령을 수행하도록 모든 엔터티를 구성합니다. EF6부터 모델의 일부 또는 모든 엔터티에 대해 저장 프로시저를 사용하도록 Code First 모델을 구성할 수 있습니다.

기본 엔터티 매핑

흐름 API를 사용하여 삽입, 업데이트 및 삭제를 위해 저장 프로시저를 사용하여 옵트인할 수 있습니다.

modelBuilder
  .Entity<Blog>()
  .MapToStoredProcedures();

그러면 Code First가 일부 규칙을 사용하여 데이터베이스에 저장 프로시저의 예상 모양을 빌드합니다.

  • <type_name>_Insert, <type_name>_Update, <type_name>_Delete(예: Blog_Insert, Blog_Update, Blog_Delete)라는 세 저장 프로시져가 있습니다.
  • 매개 변수 이름은 속성 이름에 해당합니다.

    참고 항목

    HasColumnName() 또는 Column 특성을 사용하여 지정된 속성의 열 이름을 바꾸는 경우 이 이름은 속성 이름 대신 매개 변수에 사용됩니다.

  • 삽입 저장 프로시저에는 생성된 저장소(ID 또는 계산)로 표시된 속성을 제외한 모든 속성에 대한 매개 변수가 있습니다. 저장 프로시저는 생성된 각 저장소 속성에 대한 열이 있는 결과 집합을 반환해야 합니다.
  • 업데이트 저장 프로시저에는 '계산'의 저장소 생성 패턴으로 표시된 속성을 제외한 모든 속성에 대한 매개 변수가 있습니다. 일부 동시성 토큰에는 원래 값에 대한 매개 변수가 필요하며, 자세한 내용은 아래 동시성 토큰 섹션을 참조하세요. 저장 프로시저는 각 계산 속성에 대한 열이 있는 결과 집합을 반환해야 합니다.
  • 삭제 저장 프로시저에는 엔터티의 키 값에 대한 매개 변수(또는 엔터티에 복합 키가 있는 경우 여러 매개 변수)가 있어야 합니다. 또한 삭제 프로시저에는 대상 테이블의 독립 연결 외래 키에 대한 매개 변수도 있어야 합니다(엔터티에 선언된 해당 외래 키 속성이 없는 관계). 일부 동시성 토큰에는 원래 값에 대한 매개 변수가 필요하며, 자세한 내용은 아래 동시성 토큰 섹션을 참조하세요.

다음 클래스를 예제로 사용합니다.

public class Blog  
{  
  public int BlogId { get; set; }  
  public string Name { get; set; }  
  public string Url { get; set; }  
}

기본 저장 프로시저는 다음과 같습니다.

CREATE PROCEDURE [dbo].[Blog_Insert]  
  @Name nvarchar(max),  
  @Url nvarchar(max)  
AS  
BEGIN
  INSERT INTO [dbo].[Blogs] ([Name], [Url])
  VALUES (@Name, @Url)

  SELECT SCOPE_IDENTITY() AS BlogId
END
CREATE PROCEDURE [dbo].[Blog_Update]  
  @BlogId int,  
  @Name nvarchar(max),  
  @Url nvarchar(max)  
AS  
  UPDATE [dbo].[Blogs]
  SET [Name] = @Name, [Url] = @Url     
  WHERE BlogId = @BlogId;
CREATE PROCEDURE [dbo].[Blog_Delete]  
  @BlogId int  
AS  
  DELETE FROM [dbo].[Blogs]
  WHERE BlogId = @BlogId

기본값 재정의

기본적으로 구성된 항목의 일부 또는 전체를 재정의할 수 있습니다.

하나 이상의 저장 프로시저 이름을 변경할 수 있습니다. 이 예제에서는 업데이트 저장 프로시저의 이름만 바꿉니다.

modelBuilder  
  .Entity<Blog>()  
  .MapToStoredProcedures(s =>  
    s.Update(u => u.HasName("modify_blog")));

이 예제에서는 세 저장 프로시저의 이름을 모두 바꿉니다.

modelBuilder  
  .Entity<Blog>()  
  .MapToStoredProcedures(s =>  
    s.Update(u => u.HasName("modify_blog"))  
     .Delete(d => d.HasName("delete_blog"))  
     .Insert(i => i.HasName("insert_blog")));

이러한 예제에서는 호출이 함께 연결되지만 람다 블록 구문을 사용할 수도 있습니다.

modelBuilder  
  .Entity<Blog>()  
  .MapToStoredProcedures(s =>  
    {  
      s.Update(u => u.HasName("modify_blog"));  
      s.Delete(d => d.HasName("delete_blog"));  
      s.Insert(i => i.HasName("insert_blog"));  
    });

다음은 업데이트 저장 프로시저에서 BlogId 속성의 매개 변수 이름을 바꾸는 예제입니다.

modelBuilder  
  .Entity<Blog>()  
  .MapToStoredProcedures(s =>  
    s.Update(u => u.Parameter(b => b.BlogId, "blog_id")));

이러한 호출은 모두 연결 가능하고 구성 가능합니다. 다음은 세 저장 프로시저 및 해당 매개 변수의 이름을 모두 바꾸는 예제입니다.

modelBuilder  
  .Entity<Blog>()  
  .MapToStoredProcedures(s =>  
    s.Update(u => u.HasName("modify_blog")  
                   .Parameter(b => b.BlogId, "blog_id")  
                   .Parameter(b => b.Name, "blog_name")  
                   .Parameter(b => b.Url, "blog_url"))  
     .Delete(d => d.HasName("delete_blog")  
                   .Parameter(b => b.BlogId, "blog_id"))  
     .Insert(i => i.HasName("insert_blog")  
                   .Parameter(b => b.Name, "blog_name")  
                   .Parameter(b => b.Url, "blog_url")));

데이터베이스에서 생성된 값을 포함하는 결과 집합의 열 이름을 변경할 수도 있습니다.

modelBuilder
  .Entity<Blog>()
  .MapToStoredProcedures(s =>
    s.Insert(i => i.Result(b => b.BlogId, "generated_blog_identity")));
CREATE PROCEDURE [dbo].[Blog_Insert]  
  @Name nvarchar(max),  
  @Url nvarchar(max)  
AS  
BEGIN
  INSERT INTO [dbo].[Blogs] ([Name], [Url])
  VALUES (@Name, @Url)

  SELECT SCOPE_IDENTITY() AS generated_blog_id
END

클래스에서 외래 키가 없는 관계(독립 연결)

외래 키 속성이 클래스 정의에 포함된 경우 해당 매개 변수는 다른 속성과 동일한 방식으로 이름을 바꿀 수 있습니다. 관계가 클래스에 외래 키 속성이 없는 경우 기본 매개 변수 이름은 <navigation_property_name>_<primary_key_name>입니다.

예를 들어 다음 클래스 정의를 사용하면 저장 프로시저에서 Blog_BlogId 매개 변수를 통해 게시물을 삽입하고 업데이트할 수 있습니다.

public class Blog  
{  
  public int BlogId { get; set; }  
  public string Name { get; set; }  
  public string Url { get; set; }

  public List<Post> Posts { get; set; }  
}  

public class Post  
{  
  public int PostId { get; set; }  
  public string Title { get; set; }  
  public string Content { get; set; }  

  public Blog Blog { get; set; }  
}

기본값 재정의

기본 키 속성의 경로를 Parameter 메서드에 제공하여 클래스에 포함되지 않은 외래 키에 대한 매개 변수를 변경할 수 있습니다.

modelBuilder
  .Entity<Post>()  
  .MapToStoredProcedures(s =>  
    s.Insert(i => i.Parameter(p => p.Blog.BlogId, "blog_id")));

종속 엔터티에 탐색 속성이 없는 경우(즉, Post.Blog 속성 없음) Association 메서드를 사용하여 관계의 다른 쪽 끝을 식별한 다음 각 키 속성에 해당하는 매개 변수를 구성할 수 있습니다.

modelBuilder
  .Entity<Post>()  
  .MapToStoredProcedures(s =>  
    s.Insert(i => i.Navigation<Blog>(  
      b => b.Posts,  
      c => c.Parameter(b => b.BlogId, "blog_id"))));

동시성 토큰

업데이트 및 삭제 저장 프로시저는 동시성을 처리해야 할 수도 있습니다.

  • 엔터티에 동시성 토큰이 포함된 경우 저장 프로시저에는 선택적으로 업데이트/삭제된 행 수(영향을 받는 행)를 반환하는 출력 매개 변수가 있을 수 있습니다. 이러한 매개 변수는 RowsAffectedParameter 메서드를 사용하여 구성해야 합니다.
    기본적으로 EF는 ExecuteNonQuery의 반환 값을 사용하여 영향을 받은 행 수를 확인합니다. 영향을 받는 행 출력 매개 변수 지정은 실행이 끝날 때 ExecuteNonQuery의 반환 값이 잘못되는(EF의 관점에서) 스프록에서 논리를 수행하는 경우에 유용합니다.
  • 각 동시성 토큰에는 <property_name>_Original(예: Timestamp_Original)이라는 매개 변수가 있습니다. 데이터베이스에서 쿼리할 때의 값인 이 속성의 원래 값이 전달됩니다.
    • 타임스탬프와 같이 데이터베이스에서 계산하는 동시성 토큰에는 원래 값 매개 변수만 있습니다.
    • 동시성 토큰으로 설정된 계산되지 않은 속성에는 업데이트 프로시저의 새 값에 대한 매개 변수도 있습니다. 이는 새 값에 대해 이미 설명된 명명 규칙을 사용합니다. 이러한 토큰의 예는 블로그의 URL을 동시성 토큰으로 사용하는 것입니다. 데이터베이스에서만 업데이트되는 타임스탬프 토큰과 달리 코드에서 새 값으로 업데이트할 수 있으므로 새 값이 필요합니다.

이는 타임스탬프 동시성 토큰을 사용하여 저장 프로시저를 업데이트하는 예제 클래스입니다.

public class Blog  
{  
  public int BlogId { get; set; }  
  public string Name { get; set; }  
  public string Url { get; set; }  
  [Timestamp]
  public byte[] Timestamp { get; set; }
}
CREATE PROCEDURE [dbo].[Blog_Update]  
  @BlogId int,  
  @Name nvarchar(max),  
  @Url nvarchar(max),
  @Timestamp_Original rowversion  
AS  
  UPDATE [dbo].[Blogs]
  SET [Name] = @Name, [Url] = @Url     
  WHERE BlogId = @BlogId AND [Timestamp] = @Timestamp_Original

다음은 계산되지 않은 동시성 토큰을 사용하여 저장 프로시저를 업데이트하는 예제 클래스입니다.

public class Blog  
{  
  public int BlogId { get; set; }  
  public string Name { get; set; }  
  [ConcurrencyCheck]
  public string Url { get; set; }  
}
CREATE PROCEDURE [dbo].[Blog_Update]  
  @BlogId int,  
  @Name nvarchar(max),  
  @Url nvarchar(max),
  @Url_Original nvarchar(max),
AS  
  UPDATE [dbo].[Blogs]
  SET [Name] = @Name, [Url] = @Url     
  WHERE BlogId = @BlogId AND [Url] = @Url_Original

기본값 재정의

필요에 따라 영향을 받는 행 매개 변수를 도입할 수 있습니다.

modelBuilder  
  .Entity<Blog>()  
  .MapToStoredProcedures(s =>  
    s.Update(u => u.RowsAffectedParameter("rows_affected")));

원래 값만 전달되는 데이터베이스 계산 동시성 토큰의 경우 표준 매개 변수 이름 바꾸기 메커니즘을 사용하여 원래 값의 매개 변수 이름을 바꿀 수 있습니다.

modelBuilder  
  .Entity<Blog>()  
  .MapToStoredProcedures(s =>  
    s.Update(u => u.Parameter(b => b.Timestamp, "blog_timestamp")));

원래 값과 새 값이 모두 전달되는 계산되지 않은 동시성 토큰의 경우 매개 변수의 오버로드를 사용하여 각 매개 변수의 이름을 제공할 수 있습니다.

modelBuilder
 .Entity<Blog>()
 .MapToStoredProcedures(s => s.Update(u => u.Parameter(b => b.Url, "blog_url", "blog_original_url")));

다대다 관계

이 섹션의 예제로 다음 클래스를 사용합니다.

public class Post  
{  
  public int PostId { get; set; }  
  public string Title { get; set; }  
  public string Content { get; set; }  

  public List<Tag> Tags { get; set; }  
}  

public class Tag  
{  
  public int TagId { get; set; }  
  public string TagName { get; set; }  

  public List<Post> Posts { get; set; }  
}

다음 구문을 사용하여 다대다 관계를 저장 프로시저에 매핑할 수 있습니다.

modelBuilder  
  .Entity<Post>()  
  .HasMany(p => p.Tags)  
  .WithMany(t => t.Posts)  
  .MapToStoredProcedures();

다른 구성이 제공되지 않으면 기본적으로 다음 저장 프로시저 셰이프가 사용됩니다.

  • <type_one><type_two>_Insert<type_one><type_two>_Delete(예: PostTag_Insert 및 PostTag_Delete)라는 두 저장 프로시저가 사용됩니다.
  • 매개 변수는 각 형식의 키 값이 됩니다. 각 매개 변수의 이름은 <type_name>_<property_name>(예: Post_PostId 및 Tag_TagId)이 됩니다.

다음은 삽입 및 업데이트 저장 프로시저의 예제입니다.

CREATE PROCEDURE [dbo].[PostTag_Insert]  
  @Post_PostId int,  
  @Tag_TagId int  
AS  
  INSERT INTO [dbo].[Post_Tags] (Post_PostId, Tag_TagId)   
  VALUES (@Post_PostId, @Tag_TagId)
CREATE PROCEDURE [dbo].[PostTag_Delete]  
  @Post_PostId int,  
  @Tag_TagId int  
AS  
  DELETE FROM [dbo].[Post_Tags]    
  WHERE Post_PostId = @Post_PostId AND Tag_TagId = @Tag_TagId

기본값 재정의

프로시저 및 매개 변수 이름은 엔터티 저장 프로시저와 비슷한 방식으로 구성할 수 있습니다.

modelBuilder  
  .Entity<Post>()  
  .HasMany(p => p.Tags)  
  .WithMany(t => t.Posts)  
  .MapToStoredProcedures(s =>  
    s.Insert(i => i.HasName("add_post_tag")  
                   .LeftKeyParameter(p => p.PostId, "post_id")  
                   .RightKeyParameter(t => t.TagId, "tag_id"))  
     .Delete(d => d.HasName("remove_post_tag")  
                   .LeftKeyParameter(p => p.PostId, "post_id")  
                   .RightKeyParameter(t => t.TagId, "tag_id")));