Entity Framework 6 Code First新特性:支持存儲過程

  Entity Framework 6提供支持存儲過程的新特性,本文具體演示Entity Framework 6 Code First的存儲過程操做。數據庫

Code First的插入/修改/刪除存儲過程

  默認狀況下下,Code First配置對所有實體的插入/修改/刪除操做均直接針對表進行。從EF6開始能夠配置對所有或部分實體來選擇使用存儲過程。併發

1. 基本實體映射

1.1 經過Fluent API,配置使用插入/修改/刪除存儲過程

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

1.2 Code First在數據庫中生成存儲過程的約定

  ◊ 生成三個存儲過程,名稱分別爲<type_name>_Insert, <type_name>_Update, <type_name>_Deleteapp

  ◊ 參數名對應於屬性名 (注意:若是在 property上使用 HasColumnName() 或者 Column attribute 來重命名,那麼參數也將使用這個重命名過的名稱 );ide

  ◊ The insert stored procedure 爲每個屬性都有一個參數,除了那些標記爲數據庫產生的(identity or computed),返回結果爲那些標記爲數據庫產生的屬性列;ui

  ◊ The update stored procedure 爲每個屬性都有一個參數,除了那些標記爲數據庫產生且模式爲 computed 的。一些併發標記的須要一個表明原始值的參數。返回值爲那些 computed property 的列;this

  ◊ The delete stored procedure 參數爲實體主鍵(或者組合主鍵),此外也須要爲每個獨立關聯的外鍵準備一個參數(指那些沒有在實體上定義相應外鍵屬性的關係),一些併發標記的須要一個表明原始值的參數。spa

  示例:code

  實體文件blog.cs:blog

using System;
using System.Collections.Generic;

namespace EF6.Models
{
    public partial class Blog
    {
        public int BlogID { get; set; }
        public string Name { get; set; }
        public string Url { get; set; }
    }
}

  實體映射文件BlogMap.cs:get

using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;

namespace EF6.Models.Mapping
{
    public class BlogMap : EntityTypeConfiguration<Blog>
    {
        public BlogMap()
        {
            // Primary Key
            this.HasKey(t => t.BlogID);

            // Properties
            this.Property(t => t.Name)
                .HasMaxLength(50);

            this.Property(t => t.Url)
                .HasMaxLength(100);

            // Table & Column Mappings
            this.ToTable("Blog");
            this.Property(t => t.BlogID).HasColumnName("BlogID");
            this.Property(t => t.Name).HasColumnName("Name");
            this.Property(t => t.Url).HasColumnName("Url");

            // Procedures
            this.MapToStoredProcedures();
        }
    }
}

  在程序包管理器控制檯中依次執行:

PM> Enable-Migrations -EnableAutomaticMigrations
PM> Add-Migration InitialCreate
PM> Update-Database -Verbose

  執行完成以後生成數據庫:

  監控生成數據的SQL語句:

CREATE TABLE [dbo].[Blog] (
    [BlogID] [int] NOT NULL IDENTITY,
    [Name] [nvarchar](50),
    [Url] [nvarchar](100),
    CONSTRAINT [PK_dbo.Blog] PRIMARY KEY ([BlogID])
CREATE PROCEDURE [dbo].[Blog_Insert]
    @Name [nvarchar](50),
    @Url [nvarchar](100)
AS
BEGIN
    INSERT [dbo].[Blog]([Name], [Url])
    VALUES (@Name, @Url)
    
    DECLARE @BlogID int
    SELECT @BlogID = [BlogID]
    FROM [dbo].[Blog]
    WHERE @@ROWCOUNT > 0 AND [BlogID] = scope_identity()
    
    SELECT t0.[BlogID]
    FROM [dbo].[Blog] AS t0
    WHERE @@ROWCOUNT > 0 AND t0.[BlogID] = @BlogID
END
CREATE PROCEDURE [dbo].[Blog_Update]
    @BlogID [int],
    @Name [nvarchar](50),
    @Url [nvarchar](100)
AS
BEGIN
    UPDATE [dbo].[Blog]
    SET [Name] = @Name, [Url] = @Url
    WHERE ([BlogID] = @BlogID)
END
CREATE PROCEDURE [dbo].[Blog_Delete]
    @BlogID [int]
AS
BEGIN
    DELETE [dbo].[Blog]
    WHERE ([BlogID] = @BlogID)
END

  二、從新默認約定

  2.一、重命名存儲過程名稱

modelBuilder  
    .Entity<Blog>()  
    .MapToStoredProcedures(s =>  
        s.Update(u => u.HasName("Modify_Blog")));
modelBuilder  
    .Entity<Blog>()  
    .MapToStoredProcedures(s =>  
        s.Update(u => u.HasName("Update_Blog"))  
         .Delete(d => d.HasName("Delete_Blog"))  
         .Insert(i => i.HasName("Insert_Bblog")));
modelBuilder  
    .Entity<Blog>()  
    .MapToStoredProcedures(s =>  
    {  
           s.Update(u => u.HasName("Update_Blog"));  
           s.Delete(d => d.HasName("Delete_Blog"));  
           s.Insert(i => i.HasName("Insert_Blog"));  
     });
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;

namespace EF6.Models.Mapping
{
    public class BlogMap : EntityTypeConfiguration<Blog>
    {
        public BlogMap()
        {
            // Primary Key
            this.HasKey(t => t.BlogID);

            // Properties
            this.Property(t => t.Name)
                .HasMaxLength(50);

            this.Property(t => t.Url)
                .HasMaxLength(100);

            // Table & Column Mappings
            this.ToTable("Blog");
            this.Property(t => t.BlogID).HasColumnName("BlogID");
            this.Property(t => t.Name).HasColumnName("Name");
            this.Property(t => t.Url).HasColumnName("Url");

            // Procedures
            this.MapToStoredProcedures(s =>{
                s.Insert(u => u.HasName("Insert_Blog"));
                s.Update(u => u.HasName("Update_Blog"));
                s.Delete(u => u.HasName("Delete_Blog"));
            });
        }
    }
}
View Code

  運行以後執行的SQL語句:

EXECUTE sp_rename @objname = N'dbo.Blog_Insert', @newname = N'Insert_Blog', @objtype = N'OBJECT'
EXECUTE sp_rename @objname = N'dbo.Blog_Update', @newname = N'Update_Blog', @objtype = N'OBJECT'
EXECUTE sp_rename @objname = N'dbo.Blog_Delete', @newname = N'Delete_Blog', @objtype = N'OBJECT'

  2.二、重命名存儲過程參數名稱

modelBuilder  
  .Entity<Blog>()  
  .MapToStoredProcedures(s =>  
    s.Update(u => u.Parameter(b => b.BlogID, "Blog_ID")));
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;

namespace EF6.Models.Mapping
{
    public class BlogMap : EntityTypeConfiguration<Blog>
    {
        public BlogMap()
        {
            // Primary Key
            this.HasKey(t => t.BlogID);

            // Properties
            this.Property(t => t.Name)
                .HasMaxLength(50);

            this.Property(t => t.Url)
                .HasMaxLength(100);

            // Table & Column Mappings
            this.ToTable("Blog");
            this.Property(t => t.BlogID).HasColumnName("BlogID");
            this.Property(t => t.Name).HasColumnName("Name");
            this.Property(t => t.Url).HasColumnName("Url");

            // Procedures
            this.MapToStoredProcedures(s =>
            {
                s.Update(u => u.Parameter(b => b.BlogID, "Blog_ID"));
            });
        }
    }
}
View Code

  運行以後執行的SQL語句:

ALTER PROCEDURE [dbo].[Blog_Update]
    @Blog_ID [int],
    @Name [nvarchar](50),
    @Url [nvarchar](100)
AS
BEGIN
    UPDATE [dbo].[Blog]
    SET [Name] = @Name, [Url] = @Url
    WHERE ([BlogID] = @Blog_ID)
END
modelBuilder  
  .Entity<Blog>()  
  .MapToStoredProcedures(s =>  
    s.Update(u => u.HasName("Update_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")));

  2.三、重命名數據庫自動生成列的返回值的列名

modelBuilder 
  .Entity<Blog>() 
  .MapToStoredProcedures(s => 
    s.Insert(i => i.Result(b => b.BlogID, "generated_blog_identity")));
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;

namespace EF6.Models.Mapping
{
    public class BlogMap : EntityTypeConfiguration<Blog>
    {
        public BlogMap()
        {
            // Primary Key
            this.HasKey(t => t.BlogID);

            // Properties
            this.Property(t => t.Name)
                .HasMaxLength(50);

            this.Property(t => t.Url)
                .HasMaxLength(100);

            // Table & Column Mappings
            this.ToTable("Blog");
            this.Property(t => t.BlogID).HasColumnName("BlogID");
            this.Property(t => t.Name).HasColumnName("Name");
            this.Property(t => t.Url).HasColumnName("Url");

            // Procedures
            this.MapToStoredProcedures(s =>
            {
                s.Insert(i => i.Result(b => b.BlogID, "generated_blog_identity"));
            });
        }
    }
}
View Code

  運行以後執行的SQL語句:

ALTER PROCEDURE [dbo].[Blog_Insert]
    @Name [nvarchar](50),
    @Url [nvarchar](100)
AS
BEGIN
    INSERT [dbo].[Blog]([Name], [Url])
    VALUES (@Name, @Url)
    
    DECLARE @BlogID int
    SELECT @BlogID = [BlogID]
    FROM [dbo].[Blog]
    WHERE @@ROWCOUNT > 0 AND [BlogID] = scope_identity()
    
    SELECT t0.[BlogID] AS generated_blog_identity
    FROM [dbo].[Blog] AS t0
    WHERE @@ROWCOUNT > 0 AND t0.[BlogID] = @BlogID
END

  三、多對多關係

  兩個多對多的實體類:

using System;
using System.Collections.Generic;

namespace EF6.Models
{
    public partial class Post
    {
        public int PostID { get; set; }
        public string Title { get; set; }
        public string Content { get; set; }
        public virtual ICollection<Tag> Tags { get; set; }
    }
}
View Code
using System;
using System.Collections.Generic;

namespace EF6.Models
{
    public partial class Tag
    {
        public int TagID { get; set; }
        public string TagName { get; set; }
        public virtual ICollection<Post> Posts { get; set; }
    }
}
View Code

  映射存儲過程:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Post>()
        .HasMany(p => p.Tags)
        .WithMany(t => t.Posts)
        .MapToStoredProcedures();
}

  默認生成的存儲過程:

  ◊ 生成兩個存儲過程,命名爲 <type_one><type_two>_Insert 和 <type_one><type_two>_Delete

  ◊ 參數爲每一類型的主鍵(或組合主鍵),命名爲 <type_name>_<property_name>

  代碼運行後生成的存儲過程:

CREATE PROCEDURE [dbo].[PostTag_Insert]
    @Post_PostID [int],
    @Tag_TagID [int]
AS
BEGIN
    INSERT [dbo].[PostTags]([Post_PostID], [Tag_TagID])
    VALUES (@Post_PostID, @Tag_TagID)
END
CREATE PROCEDURE [dbo].[PostTag_Delete]
    @Post_PostID [int],
    @Tag_TagID [int]
AS
BEGIN
    DELETE [dbo].[PostTags]
    WHERE (([Post_PostID] = @Post_PostID) AND ([Tag_TagID] = @Tag_TagID))
END

   參考資料:

  http://msdn.microsoft.com/en-us/data/dn468673

相關文章
相關標籤/搜索