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>_Delete;
◊ 参数名对应于属性名 (注意:如果在 property上使用 HasColumnName() 或者 Column attribute 来重命名,那么参数也将使用这个重命名过的名称 );
◊ The insert stored procedure 为每一个属性都有一个参数,除了那些标记为数据库产生的(identity or computed),返回结果为那些标记为数据库产生的属性列;
◊ The update stored procedure 为每一个属性都有一个参数,除了那些标记为数据库产生且模式为 computed 的。一些并发标记的需要一个代表原始值的参数。返回值为那些 computed property 的列;
◊ The delete stored procedure 参数为实体主键(或者组合主键),此外也需要为每一个独立关联的外键准备一个参数(指那些没有在实体上定义相应外键属性的关系),一些并发标记的需要一个代表原始值的参数。
示例:
实体文件blog.cs:
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:
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(); this.Property(t => t.Url)
.HasMaxLength(); // 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、重新默认约定
2.1、重命名存储过程名称
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(); this.Property(t => t.Url)
.HasMaxLength(); // 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"));
});
}
}
}
运行之后执行的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.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(); this.Property(t => t.Url)
.HasMaxLength(); // 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"));
});
}
}
}
运行之后执行的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.3、重命名数据库自动生成列的返回值的列名
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(); this.Property(t => t.Url)
.HasMaxLength(); // 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"));
});
}
}
}
运行之后执行的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
3、多对多关系
两个多对多的实体类:
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; }
}
}
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; }
}
}
映射存储过程:
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
Entity Framework 6 Code First新特性:支持存储过程的更多相关文章
- Entity Framework Core 2.0 新特性
本文翻译来自:https://docs.microsoft.com/en-us/ef/core/what-is-new/index 一.模型级查询过滤器(Model-level query filte ...
- 在Entity Framework 中用 Code First 创建新的数据库
在Entity Framework 中用 Code First 创建新的数据库 (原文链接) 本文将逐步介绍怎样用Code First 创建新数据库,使用在代码中定义类和API中提供的特性(Attri ...
- AppBox升级进行时 - 拥抱Entity Framework的Code First开发模式
AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. 从Subsonic到Entity Framework Subsonic最早发布 ...
- Entity Framework 之 Code First
使用NuGet助您玩转代码生成数据————Entity Framework 之 Code First [前言] 如果是Code First老鸟或者对Entity Framework不感兴趣,就不用浪费 ...
- 创建ASP.NET Core MVC应用程序(3)-基于Entity Framework Core(Code First)创建MySQL数据库表
创建ASP.NET Core MVC应用程序(3)-基于Entity Framework Core(Code First)创建MySQL数据库表 创建数据模型类(POCO类) 在Models文件夹下添 ...
- Entity Framework Core Code First 项目实践
Entity Framework Core Code First 实践 任何一种技术的出现都是为了解决一系列特定的问题,只有了解了技术所要解决的关键问题,才能理解它的真正用途,之后,才能在实践中用好它 ...
- 【极力分享】[C#/.NET]Entity Framework(EF) Code First 多对多关系的实体增,删,改,查操作全程详细示例【转载自https://segmentfault.com/a/1190000004152660】
[C#/.NET]Entity Framework(EF) Code First 多对多关系的实体增,删,改,查操作全程详细示例 本文我们来学习一下在Entity Framework中使用Cont ...
- Entity Framework 第三篇 实体特性声明
Entity Framework中对实体的特性声明有着严格的要求 1.实体必须要有主键特性,但是如果实体没有主键特性那怎么办? public int ExecuteSqlCommand(string ...
- MVC2、MVC3、MVC4、MVC5之间的区别 以及Entity Framework 6 Code First using MVC 5官方介绍教程
现在MVC的技术日趋成熟,面对着不同版本的MVC大家不免有所迷惑 -- 它们之间有什么不同呢?下面我把我搜集的信息汇总一下,以便大家能更好的认识不同版本MVC的功能,也便于自己查阅. View Eng ...
随机推荐
- 【第二课】WEBIX 入门自学-获取WEBIX及相关资料
下载WEBIX组件库 http://webix.com/download/ WEBIX在线文档 http://docs.webix.com/ 离线的手册 下载
- 插头dp
插头dp 感受: 我觉得重点是理解,算法并不是直接想出怎样由一种方案变成另一种方案.而是方案本来就在那里,我们只是枚举状态统计了答案. 看看cdq的讲义什么的,一开始可能觉得状态很多,但其实灰常简单 ...
- java 的各种实用类库(jar包)
总列表:# dom4j # org.json # pinyin4j # sqlite-jdbc # JavaMail # JLayer # dom4j 介绍:处理 xml 的类库.采用了 Java 集 ...
- 《JavaScript高级程序设计(第3版)》阅读总结记录第一章之JavaScript简介
前言: 为什么会想到把<JavaScript 高级程序设计(第 3 版)>总结记录呢,之前写过一篇博客,研究的轮播效果,后来又去看了<JavaScript 高级程序设计(第3版)&g ...
- mac 终端 常用命令
基本命令1.列出文件ls 参数 目录名 例: 看看驱动目录下有什么:ls /System/Library/Extensions参数 -w 显示中文,-l 详细信息, -a 包括隐藏文件2 ...
- [WPF] 我的WPF自学日记2,自定义入口
在winform中入口文件就是Program.cs,而在WPF中看不到,因为它是自动生成的,可以说隐藏了,我们可以自定义一个入口文件,然后修改项目属性中的启动对象为我们自定义的入口文件. 首先新建入口 ...
- 【hihoCoder】1082: 然而沼跃鱼早就看穿了一切
题目:http://hihocoder.com/problemset/problem/1082 输入一个字符串,将其中特定的单词替换成另一个单词 代码注意点: 1. getline(istre ...
- Flume_企业中日志处理
企业中的日志存放_1 201611/20161112.log.tmp 第二天文件变为20161112.log与20161113.log.tmp 拷贝一份flume-conf.properties.te ...
- Usaco*Brownie Slicing
Description Bessie烘焙了一块巧克力蛋糕.这块蛋糕是由R*C(1 <= R,C <= 500)个小的巧克力蛋糕组成的. 第i行,第j列的蛋糕有N_ij(1 <= N_ ...
- 仿JQ基础架构,可扩展。
(function(win,doc,fn){ var events = [];//拷贝核心方法 var publicEvent = ["extend","f ...