次の方法で共有


ストアド プロシージャの最初の挿入、更新、および削除をコードで行う

EF6 以降のみ - このページで説明されている機能、API などが Entity Framework 6 で導入されました。 以前のバージョンを使用している場合、一部またはすべての情報は適用されません。

既定では、Code First では、直接テーブル アクセスを使用して挿入、更新、および削除コマンドを実行するようにすべてのエンティティが構成されます。 EF6 以降では、モデル内の一部またはすべてのエンティティにストアド プロシージャを使用するように Code First モデルを構成できます。

基本的なエンティティ マッピング

Fluent API を使用して、挿入、更新、削除にストアド プロシージャを使用することを選択できます。

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

これを行うと、Code First でいくつかの規則を使用して、データベース内のストアド プロシージャの予想される形状が構築されます。

  • >、>という名前の 3 つのストアド プロシージャ (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

既定値のオーバーライド

既定で構成されたものの一部またはすべてをオーバーライドできます。

1 つ以上のストアド プロシージャの名前を変更できます。 この例では、更新ストアド プロシージャの名前のみを変更します。

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

この例では、3 つのストアド プロシージャの名前をすべて変更します。

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")));

これらの呼び出しはすべてチェーン可能で構成可能です。 3 つのストアド プロシージャとそのパラメーターの名前をすべて変更する例を次に示します。

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>です。

たとえば、次のクラス定義を使用すると、ストアド プロシージャで Posts を挿入および更新するために、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 の観点から) 結果として得られるロジックを sproc で実行する場合に便利です。
  • コンカレンシー トークンごとに、 <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();

他の構成が指定されていない場合は、既定で次のストアド プロシージャ図形が使用されます。

  • >という名前の 2 つのストアド プロシージャ (たとえば、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")));