Entity Frameworkmysql insert 带外键键新增记录该怎么弄

26701人阅读
与Entity Framework相伴的日子痛并快乐着。今天和大家分享一下一个快乐,两个痛苦。
先说快乐的吧。Entity Framework在将数据插入数据库时,如果主键字段是自增标识列,会将该自增值返回给实体对象对应的属性。
比如下面添加博客随笔至数据库的示例代码:
var blogPost = new BlogPost(){
Author = &博客园&,
Title = &程序员的网上家园&};using (BlogDbContext context = new BlogDbContext()){
context.BlogPosts.Add(blogPost);
context.SaveChanges();
return blogPost.ID;}
SaveChanges()之后,blogPost.ID的值就是数据库中对应自增标识列的值。
看一下Entity Framework生成的SQL语句:
exec sp_executesql N'insert [dbo].[blog_Content]([Title],[Author])values (@0, @1)select [ID]from [dbo].[blog_Content]where @@ROWCOUNT & 0 and [ID] = scope_identity()',N'@0 nvarchar(128),@1 nvarchar(128),',@0=N'程序员的网上家园',@1=N'博客园'
EF通过scope_identity()获取自增列的值,而且我们没有对BlogPost的ID属性进行任何设置,是EF智能地判断出ID就是自增标识列。
在以前没有使用Entity Framework的时代,用的是存储过程,存储过程有一堆参数,实体对象的属性值要一一对应地赋值给这些参数,执行存储过程之后,还要通过ParameterDirection.Output的参数获取自增ID的值。
现在,只要把东西交给Entity Framework,并和她说,把它放到数据库中去。多省心!多快乐!
但是,自以为是的Entity Framework用这个特性给人快乐的同时,也给人带来了一点痛苦。她认为只要实体类中有ID属性,数据库对应的是一定是自增标识列,真是够自以为是的。当我们把博客随笔添加至数据库后,准备用这个自增ID将随笔内容添加至数据库(随笔内容存储在单独的数据库,通过ID字段与随笔进行关联,不是自增的),却出现错误提示:
Cannot insert the value NULL into column 'ID',&table 'CNBlogsText.dbo.blog_PostBody'; column does not allow nulls.
看看EF生成的SQL语句:
exec sp_executesql N'insert [dbo].[CNBlogsText_blog_PostBody]([Text])values (@0)select [ID]from [dbo].[CNBlogsText_blog_PostBody]where @@ROWCOUNT & 0 and [ID] = scope_identity()',N'@0 nvarchar(128)',@0=N'帮助程序员用技术改变世界'
不是自增列,也来个scope_identity()。这么聪明的Entity Framework,也会干这样的傻事。
还好,EF定制灵活的特性可以让我们轻松化解这个痛苦,只要在BlogDbContext中添加下面的代码:
protected override void OnModelCreating(DbModelBuilder modelBuilder){
modelBuilder.Entity&PostBody&().Property(p =& p.ID)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None); }
也可以通过在实体类属性上加标记实现:
public class BlogPost{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int ID { get; set; }}
第二个痛苦是众所周知的Entity Framework不支持枚举类型,虽然大家都知道,但还是想拿出晒晒,解解恨。
EF怎么对待枚举类型的呢?对于实体类中实实在在存在的枚举类型的属性,EF对它们视而不见,就当它不存在。
对于这个痛苦,目前无法化解(要等EF的下一版本),只能借助旁边左道减轻痛苦,请看“旁边左道”之“移花接木”。
实体类中的代码:
public class BlogPost{
public BlogPostType PostType
get { return (BlogPostType)PostTypeEf; }
set { PostTypeEf = (int) }
public int PostTypeEf { get; set; }}
EF不认枚举类型,但认int类型,所以增加个PostTypeEf,仅供EF专用,等EF的下一版本支持枚举类型时再去掉。
BlogDbContext也要
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
积分:61245
积分:61245
排名:第42名
原创:673篇
转载:2209篇
评论:539条
(31)(15)(15)(7)(22)(15)(22)(13)(10)(15)(10)(10)(10)(8)(30)(19)(19)(16)(1)(9)(7)(19)(13)(9)(4)(5)(28)(12)(34)(5)(3)(13)(27)(18)(11)(3)(23)(24)(31)(42)(12)(34)(19)(37)(41)(39)(56)(146)(66)(78)(78)(6)(15)(28)(26)(17)(57)(46)(25)(41)(24)(37)(70)(72)(28)(30)(35)(49)(54)(27)(25)(16)(21)(13)(24)(26)(35)(31)(27)(6)(6)(2)(3)(3)(7)(5)(10)(4)(9)(3)(2)(11)(11)(23)(5)(1)(9)(16)(11)(14)(4)(4)(28)(17)(37)(411)(2)(7)(1)(3)(4)(7)(6)(10)(28)(7)(6)
(window.slotbydup = window.slotbydup || []).push({
id: '4740887',
container: s,
size: '250,250',
display: 'inlay-fix'sponsored links
Entity Framework Code First主外键关系映射约定
  本篇随笔目录:
  1、外键列名默认约定
  2、一对多关系
  3、一对一关系
  4、多对多关系
  5、一对多自反关系
  6、多对多自反关系
  在关系数据库中,不同表之间往往不是全部都单独存在,而是相互存在关联的。两个不同表之间可以存在外键依赖关系,一个表自身也可以有自反关系(表中的一个字段引用主键,从而也是外键字段)。
  Entity Framework Code First默认多重关系的一些约定规则:
  一对多关系:两个类中分别包含一个引用和一个集合属性,也可以是一个类包含另一个类的引用属性,或一个类包含另一个类的集合属性。如在本篇接下来用到的例子Category类和Product类,要使得Category与Product之间具有一对多关系,Entity Framework Code First可以有3种体现方式:
  1&、在Category类中定义ICollection&Product& Products集合属性,同时在Product类中定义Category Category引用属性。
  2&、仅在Category类中定义ICollection&Product& Products集合属性。
  3&、仅在Product类中定义Category Category引用属性。
  多对多关系:两个类分别包含对方的一个集合属性。如在本篇接下来用到的例子User类和Role类,要使得User与Role之间具有多对多关系,即一个用户可以属于多个角色,一个角色可以有多个用户,则需要在User类中需要定义一个ICollection&Role& Roles集合属性,同时在Role类中需要定义一个ICollection&User& Users属性。
  一对一关系:两个类分别包含对方的一个引用属性。如在本篇接下来用到的例子User类和UserProfile类,要使得User与UserProfile之间具有一对一关系,则需要在User类中定义一个UserProfile UserProfile的引用属性,同时在UserProfile类中定义一个User User的引用属性。
  下面具体描述Entity Framework Code First生成外键的默认约定,并通过实例展示Entity Framework Code First处理一个表及多个表之间的关系。
  1、外键列名默认约定
  Entity Framework Code First在根据默认约定创建外键时,外键列的名称存在3种方式。在《Programming Entity Framework Code First》一书中,给出的3种外键列名的约定方式是:[Target Type Key Name], [Target Type Name] + [Target Type Key Name], or [Navigation Property Name] + [Target Type Key Name],对应的中文翻译为:[目标类型的键名],[目标类型名称]+[目标类型键名称],或[引用属性名称]+[目标类型键名称]。
  Entity Framework Code First外键默认约束生成的外键在分别满足3种不同的条件下,外键列名有3种不同的命名规则。且经过测试这3种不同的外键名称命名之间存在优先级:[目标类型的键名] &&[引用属性名称]+[目标类型键名称] &&[目标类型名称]+[目标类型键名称]。接下来以Product类及Category类为例,分别测试外键列名称的3中不同生成方式,Category与Product为一对多关系。
  1&、[目标类型的键名]
  这种方式为要求在Product表中外键列名与Category表中的主键列名相同,所以也就要求在Product类中有定义与Category类中作为主键的属性。如在Category类中主键属性为CategoryID,则需要在Product类中也定义一个CategoryID的属性。
  文件Category.cs:
using System.Collections.G
using System.L
using System.T
namespace Portal.Entities
public class Category
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public virtual ICollection&Product& Products { get; set; }
  文件Product.cs:
using System.Collections.G
using System.L
using System.T
namespace Portal.Entities
public class Product
public int ProductID { get; set; }
public string ProductName { get; set; }
public decimal UnitPrice { get; set; }
public int CategoryID { get; set; }
public virtual Category Category { get; set; }
  说明:在Category类及Product类中的引用属性及集合属性前加virtual修饰,为的是Entity Framework Code First的延迟加载功能。不使用virtual修饰,在Category类的一个实例要查询包含的Product实例时,将不会启用延迟加载。当然Entity Framework Code First延迟加载并不是必须的,所以virtual修饰符也可以不加。
  在定义以上两个类之后,不再添加任何的Entity Framework Code First与数据库的映射配置,运行之后,生成的数据表结构为:
  从生成的Categories与Products表结构可以看出,在Products表中的外键CategoryID与引用的表Categories主键名称相同。跟踪Entity Framework Code First生成数据表的执行脚本可以看到具体生成外键的SQL语句。
ALTER TABLE [dbo].[Products] ADD CONSTRAINT [FK_dbo.Products_dbo.Categories_CategoryID] FOREIGN KEY ([CategoryID]) REFERENCES [dbo].[Categories] ([CategoryID]) ON DELETE CASCADE
  同时,从生成外键的脚本还能看出一点,Entity Framework Code First生成外键是启用级联删除功能的。即当删除Categories表中一条记录时,数据库会自动联带删除Products表中属于该类别的记录。
  在数据库中生成的Products表,查看外键FK_dbo.Products_dbo.Categories_CategoryID属性,其的确有启用级联删除功能。
  2&、[目标类型名称]+[目标类型键名称]
  这种方式要求在Product表中外键列名为Category类名+Category类中键名称,即在Products表中生成的外键名称为Category_CategoryID。示例:在Category类中添加ICollection&Product& Products的集合属性,而在Product类中不做任何与Category关联的代码,也不定义CategoryID属性。
  文件Category.cs:
using System.Collections.G
using System.L
using System.Text;
namespace Portal.Entities
public class Category
public int CategoryID { set; }
public string CategoryName { set; }
public virtual ICollection&Product& Products { set; }
  文件Product.cs:
using System.Collections.G
using System.L
using System.Text;
namespace Portal.Entities
public class Product
public int ProductID { set; }
public string ProductName { set; }
public decimal UnitPrice { set; }
  在定义以上两个类之后,不再添加任何的Entity Framework Code First与数据库的映射配置,运行之后,生成的数据表结构为:
&  3&、[引用属性名称]+[目标类型键名称]
  这种方式为要求在Product表中外键列名为在Product类中引用Category的属性名称 + Category类的主键名称。如:在Product类中定义一个Category属性Cat,则生成的外键名称为Cat_CategoryID。
  文件Category.cs:
using System.Collections.G
using System.L
using System.Text;
namespace Portal.Entities
public class Category
public int CategoryID { set; }
public string CategoryName { set; }
  文件Product.cs:
using System.Collections.G
using System.L
using System.Text;
namespace Portal.Entities
public class Product
public int ProductID { set; }
public string ProductName { set; }
public decimal UnitPrice { set; }
/// &summary&
/// 这里为演示,使用Cat作为Category的缩写。
/// &/summary&
public virtual Category Cat { set; }
  在定义以上两个类之后,不再添加任何的Entity Framework Code First与数据库的映射配置,运行之后,生成的数据表结构为:
  关于3种不同的外键名称命名之间存在优先级:[目标类型的键名] & [引用属性名称]+[目标类型键名称] & [目标类型名称]+[目标类型键名称]的测试方法:
  [目标类型的键名]的最高优先级:只要在Product类中定义了CategoryID的属性,在Products表中生成的外键列名都只会为CategoryID。
  [引用属性名称]+[目标类型键名称] & [目标类型名称]+[目标类型键名称]:只要在Product类中定义Cat属性,不管Category类中是否定义Products属性,生成的Products表中外键都只会是Cat_CategoryID。
  2、一对多关系
  Entity Framework Code First在根据定义的类生成数据表时,数据表之间的外键关系及所生成的外键列名有默认的约定。但这种约定同样可以进行修改,如将不满足默认外键约定的属性来作为生成表的外键。示例:Category类与Product类,在Product类中定义一个属性CatID,要将CatID属性作为Product的引用Category的外键,而按照Entity Framework Code First的默认约定是不会的。要做到需要的CatID作为外键,同样可以使用Data Annotations和Fluent API两种方式实现。
  1&、Data Annotations方式
  文件类Category.cs:
using System.Collections.G
using System.L
using System.T
namespace Portal.Entities
public class Category
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public virtual ICollection&Product& Products { get; set; }
  文件类Product.cs:
using System.Collections.G
using System.L
using System.T
using ponentModel.DataAnnotations.S
namespace Portal.Entities
public class Product
public int ProductID { get; set; }
public string ProductName { get; set; }
public decimal UnitPrice { get; set; }
public int CatID { get; set; }
[ForeignKey("CatID")]
public virtual Category Category { get; set; }
  在定义以上两个类之后,不再添加任何的Entity Framework Code First与数据库的映射配置,运行之后,生成的数据表结构为:
  查看Products表的外键咧CatID引用关系:
  其中,在Product类中,为设置CatID属性为外键的代码为:
public int CatID { get; set; }
[ForeignKey("CatID")]
public virtual Category Category { get; set; }
  该段实现方式还可以改为:
[ForeignKey("Category")]
public int CatID { get; set; }
public virtual Category Category { get; set; }
  2&、Fluent API方式
  文件类Category.cs:
using System.Collections.G
using System.L
using System.T
namespace Portal.Entities
public class Category
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public virtual ICollection&Product& Products { get; set; }
  文件类Product.cs:
using System.Collections.G
using System.L
using System.T
namespace Portal.Entities
public class Product
public int ProductID { get; set; }
public string ProductName { get; set; }
public decimal UnitPrice { get; set; }
public int CatID { get; set; }
public virtual Category Category { get; set; }
  文件类PortalContext.cs:
using System.Collections.G
using System.L
using System.T
using System.Data.E
using Portal.E
namespace Portal
public class PortalContext : DbContext
static PortalContext()
Database.SetInitializer(new DropCreateDatabaseIfModelChanges&PortalContext&());
public DbSet&Category& Categories { get; set; }
public DbSet&Product& Products { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
modelBuilder.Entity&Category&()
.HasMany(t =& t.Products)
.WithRequired(t =& t.Category)
.HasForeignKey(d =& d.CatID);
modelBuilder.Entity&Product&()
.HasRequired(t =& t.Category)
.WithMany(t =& t.Products)
.HasForeignKey(d =& d.CatID);
  说明:在PortalContext.cs的OnModelCreating方法中,对两个实体类Category及Product均添加了Fluent API形式的关系配置。对于Entity Framework Code First而言,两个实体类之间的关系,可以两个类中均添加关系映射配置,也可以只对其中任意一个实体类添加关系映射配置。即在PortalContext.cs的OnModelCreating方法中可以只包含Category或只包含Product类的关系映射配置。这里从Entity Framework Code First的使用经验及技巧,建议将实体类之间关系映射配置在包含外键的类中。即OnModelCreating中只添加对Product实体类的关系映射配置,这样做有一个好处,当Category有多个表引用它时,可以将外键均配置在引用它的实体类中,从而降低Category类的复杂度,同时也有益于代码的维护。
  即在PortalContext.cs的OnModelCreating方法只需下面的定义即可:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
modelBuilder.Entity&Product&()
.HasRequired(t =& t.Category)
.WithMany(t =& t.Products)
.HasForeignKey(d =& d.CatID);
  Entity Framework Code First根据一对多关系关系生成的外键引用约束默认是有级联删除的,可以通过以下方式禁用Category与Product之间的级联删除。
protected override void OnModelCreating(DbModelBuilder modelBuilder)
modelBuilder.Entity&Product&()
.HasRequired(t =& t.Category)
.WithMany(t =& t.Products)
.HasForeignKey(d =& d.CatID)
.WillCascadeOnDelete(false);
  也可以在Entity Framework Code First生成的全部表中都统一设置禁用一对多级联删除。
protected override void OnModelCreating(DbModelBuilder modelBuilder)
modelBuilder.Conventions.Remove&OneToManyCascadeDeleteConvention&();
  虽然Entity Framework Code First是可以支持外键列名自定义的,但在实际的项目中,更多的外键列名称还是与所引用表的主键列名相同。即在Category表中主键为CategoryID,在Product表中外键列名称还是为CategoryID。
  Entity Framework Code First的Fluent API配置实体类与表的映射关系,还可以将所有的实体类与表的映射全部写在一个类中,这样可以方便代码的维护。
  文件类Category.cs:
using System.Collections.G
using System.L
using System.T
namespace Portal.Entities
public partial class Category
public Category()
this.Products = new List&Product&();
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public virtual ICollection&Product& Products { get; set; }
  文件类CategoryMap.cs,用于描述Category类与生成的表之间的映射关系:
using System.Collections.G
using System.L
using System.T
using ponentModel.DataAnnotations.S
using System.Data.Entity.ModelC
using Portal.E
namespace Portal.Mapping
public class CategoryMap : EntityTypeConfiguration&Category&
public CategoryMap()
// Primary Key
this.HasKey(t =& t.CategoryID);
// Properties
this.Property(t =& t.CategoryName)
.IsRequired()
.HasMaxLength(50);
// Table & Column Mappings
this.ToTable("Category");
this.Property(t =& t.CategoryID).HasColumnName("CategoryID");
this.Property(t =& t.CategoryName).HasColumnName("CategoryName");
  文件类Product.cs:
using System.Collections.G
namespace Portal.Entities
public partial class Product
public int ProductID { get; set; }
public int CategoryID { get; set; }
public string ProductName { get; set; }
public Nullable&decimal& UnitPrice { get; set; }
public Nullable&int& Quantity { get; set; }
public virtual Category Category { get; set; }
  文件类ProductMap.cs,用于描述Product类与生成的表之间的映射关系:
using System.Collections.G
using System.L
using System.T
using ponentModel.DataAnnotations.S
using System.Data.Entity.ModelC
using Portal.E
namespace Portal.Mapping
public class ProductMap : EntityTypeConfiguration&Product&
public ProductMap()
// Primary Key
this.HasKey(t =& t.ProductID);
// Properties
this.Property(t =& t.ProductName)
.IsRequired()
.HasMaxLength(100);
// Table & Column Mappings
this.ToTable("Product");
this.Property(t =& t.ProductID).HasColumnName("ProductID");
this.Property(t =& t.CategoryID).HasColumnName("CategoryID");
this.Property(t =& t.ProductName).HasColumnName("ProductName");
this.Property(t =& t.UnitPrice).HasColumnName("UnitPrice");
this.Property(t =& t.Quantity).HasColumnName("Quantity");
// Relationships
this.HasRequired(t =& t.Category)
.WithMany(t =& t.Products)
.HasForeignKey(d =& d.CategoryID);
  PortalContext.cs的OnModelCreating方法:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
modelBuilder.Configurations.Add(new CategoryMap());
modelBuilder.Configurations.Add(new ProductMap());
  3、一对一关系
&  在一对一关系中,两个表均有各自的主键,但要看哪个表的主键同时作为外键引用另一个表的主键。示例以User类与UserProfile类作为两个具有一对一关系的类,其中User类包含作为主键的UserID属性,UserProfile类包含作为主键的ProfileID的属性。
  1&、Data Annotations方式
  文件类User.cs:
using System.Collections.G
using ponentModel.DataA
using ponentModel.DataAnnotations.S
namespace Portal.Entities
public partial class User
public int UserID { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public Nullable&bool& IsValid { get; set; }
public virtual UserProfile UserProfile { get; set; }
  文件类UserProfile.cs:
using System.Collections.G
using ponentModel.DataA
using ponentModel.DataAnnotations.S
namespace Portal.Entities
public partial class UserProfile
[ForeignKey("User")]
public int ProfileID { get; set; }
public string Name { get; set; }
public Nullable&bool& Sex { get; set; }
public Nullable&DateTime& Birthday { get; set; }
public string Email { get; set; }
public string Telephone { get; set; }
public string Mobilephone { get; set; }
public string Address { get; set; }
public Nullable&DateTime& CreateDate { get; set; }
public virtual User User { get; set; }
  在定义以上两个类之后,不再添加任何的Entity Framework Code First与数据库的映射配置,运行之后,生成的数据表结构为:
  在生成的数据表中,UserProfile表中的主键ProfileID同时也作为外键引用User表中的主键UserID。
  修改文件类User.cs:
using System.Collections.G
using ponentModel.DataA
using ponentModel.DataAnnotations.S
namespace Portal.Entities
public partial class User
[ForeignKey("UserProfile")]
public int UserID { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public Nullable&bool& IsValid { get; set; }
public virtual UserProfile UserProfile { get; set; }
  修改文件类UserProfile.cs:
using System.Collections.G
using ponentModel.DataA
using ponentModel.DataAnnotations.S
namespace Portal.Entities
public partial class UserProfile
public int ProfileID { get; set; }
public string Name { get; set; }
public Nullable&bool& Sex { get; set; }
public Nullable&DateTime& Birthday { get; set; }
public string Email { get; set; }
public string Telephone { get; set; }
public string Mobilephone { get; set; }
public string Address { get; set; }
public Nullable&DateTime& CreateDate { get; set; }
public virtual User User { get; set; }
  则实体类执行之后生成的数据表User主键UserID将同时作为外键引用UserProfile表的主键ProfileID。
  2&、Fluent API方式
  Fluent API设置实体类生成的表引用与被引用通过WithRequiredPrincipal、WithRequiredDependent及WithOptionalPrincipal、WithOptionalDependent来设置,使用Principal属性的实体类将被另外的实体类生成的表引用,使用Dependent属性的实体类将引用另外的实体类。
  文件类User.cs:
using System.Collections.G
using ponentModel.DataA
using ponentModel.DataAnnotations.S
namespace Portal.Entities
public partial class User
public int UserID { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public Nullable&bool& IsValid { get; set; }
public virtual UserProfile UserProfile { get; set; }
  映射文件类UserMap.cs:
using System.Collections.G
using System.L
using System.T
using ponentModel.DataAnnotations.S
using System.Data.Entity.ModelC
using Portal.E
namespace Portal.Mapping
public class UserMap : EntityTypeConfiguration&User&
public UserMap()
// Primary Key
this.HasKey(t =& t.UserID);
// Properties
this.Property(t =& t.UserName)
.HasMaxLength(50);
this.Property(t =& t.Password)
.HasMaxLength(100);
// Table & Column Mappings
this.ToTable("User");
this.Property(t =& t.UserID).HasColumnName("UserID");
this.Property(t =& t.UserName).HasColumnName("UserName");
this.Property(t =& t.Password).HasColumnName("Password");
this.Property(t =& t.IsValid).HasColumnName("IsValid");
  文件类UserProfile.cs:
using System.Collections.G
namespace Portal.Entities
public partial class UserProfile
public int UserID { get; set; }
public string Name { get; set; }
public Nullable&bool& Sex { get; set; }
public Nullable&DateTime& Birthday { get; set; }
public string Email { get; set; }
public string Telephone { get; set; }
public string Mobilephone { get; set; }
public string Address { get; set; }
public Nullable&DateTime& CreateDate { get; set; }
public virtual User User { get; set; }
  映射文件类UserProfileMap.cs:
using System.Collections.G
using System.L
using System.T
using ponentModel.DataAnnotations.S
using System.Data.Entity.ModelC
using Portal.E
namespace Portal.Mapping
public class UserProfileMap : EntityTypeConfiguration&UserProfile&
public UserProfileMap()
// Primary Key
this.HasKey(t =& t.UserID);
// Properties
this.Property(t =& t.UserID)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.Property(t =& t.Name)
.IsRequired()
.HasMaxLength(50);
this.Property(t =& t.Email)
.IsRequired()
.HasMaxLength(100);
this.Property(t =& t.Telephone)
.HasMaxLength(50);
this.Property(t =& t.Mobilephone)
.HasMaxLength(20);
this.Property(t =& t.Address)
.HasMaxLength(200);
// Table & Column Mappings
this.ToTable("UserProfile");
this.Property(t =& t.UserID).HasColumnName("UserID");
this.Property(t =& t.Name).HasColumnName("Name");
this.Property(t =& t.Sex).HasColumnName("Sex");
this.Property(t =& t.Birthday).HasColumnName("Birthday");
this.Property(t =& t.Email).HasColumnName("Email");
this.Property(t =& t.Telephone).HasColumnName("Telephone");
this.Property(t =& t.Mobilephone).HasColumnName("Mobilephone");
this.Property(t =& t.Address).HasColumnName("Address");
this.Property(t =& t.CreateDate).HasColumnName("CreateDate");
// Relationships
this.HasRequired(t =& t.User)
.WithRequiredDependent(t =& t.UserProfile);
  在以上实体类及实体映射类执行以后,生成的数据表结构如下:
  在生成的表结构中,UserProfile表中的主键UserID同时也作为外键引用User表的主键UserID。若修改UserProfileMap.cs如下,则生成的表结构User表的主键UserID将作为你外键引用UserProfile表的主键UserID。
using System.Collections.G
using System.L
using System.T
using ponentModel.DataAnnotations.S
using System.Data.Entity.ModelC
using Portal.E
namespace Portal.Mapping
public class UserProfileMap : EntityTypeConfiguration&UserProfile&
public UserProfileMap()
// Primary Key
this.HasKey(t =& t.UserID);
// Properties
this.Property(t =& t.UserID)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.Property(t =& t.Name)
.IsRequired()
.HasMaxLength(50);
this.Property(t =& t.Email)
.IsRequired()
.HasMaxLength(100);
this.Property(t =& t.Telephone)
.HasMaxLength(50);
this.Property(t =& t.Mobilephone)
.HasMaxLength(20);
this.Property(t =& t.Address)
.HasMaxLength(200);
// Table & Column Mappings
this.ToTable("UserProfile");
this.Property(t =& t.UserID).HasColumnName("UserID");
this.Property(t =& t.Name).HasColumnName("Name");
this.Property(t =& t.Sex).HasColumnName("Sex");
this.Property(t =& t.Birthday).HasColumnName("Birthday");
this.Property(t =& t.Email).HasColumnName("Email");
this.Property(t =& t.Telephone).HasColumnName("Telephone");
this.Property(t =& t.Mobilephone).HasColumnName("Mobilephone");
this.Property(t =& t.Address).HasColumnName("Address");
this.Property(t =& t.CreateDate).HasColumnName("CreateDate");
// Relationships
this.HasRequired(t =& t.User)
.WithRequiredPrincipal(t =& t.UserProfile);
  4、多对多关系
  Entity Framework Code First在根据定义的多对多关系的类生成数据表时,除了生成实体类定义的属性表之外,还会生成一个中间表。用于体现两个实体表之间的多对多的关系。示例实体类User与Role为多对多关系,一个用户可以属于多个角色,一个角色可以包含多个用户。
  文件类User.cs:
using System.Collections.G
namespace Portal.Entities
public partial class User
public int UserID { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public Nullable&bool& IsValid { get; set; }
public virtual ICollection&Role& Roles { get; set; }
  文件类Role.cs:
using System.Collections.G
namespace Portal.Entities
public partial class Role
public Role()
this.Users = new List&User&();
public int RoleID { get; set; }
public string RoleName { get; set; }
public virtual ICollection&User& Users { get; set; }
  在定义以上两个类之后,不再添加任何的Entity Framework Code First与数据库的映射配置,运行之后,生成的数据表结构为:
  从以上的表结构中,可以看出,实体类运行之后,除了生成Users表和Roles表之外,还生成了RoleUsers表作为中介表,体现Users表和Roles表之间的多对多关联关系。中介表RoleUsers的字段生成规则按照 [目标类型名称]+[目标类型键名称] 的约定。
  Entity Framework Code First根据默认约定生成的多对多关联关系的表时,默认启用多对多的数据级联删除,可以添加代码进行禁用。
protected override void OnModelCreating(DbModelBuilder modelBuilder)
// 禁用多对多关系表的级联删除
modelBuilder.Conventions.Remove&ManyToManyCascadeDeleteConvention&();
  FluentAPI实现方式:
  文件类User.cs:
using System.Collections.G
namespace Portal.Entities
public partial class User
public int UserID { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public Nullable&bool& IsValid { get; set; }
public virtual ICollection&Role& Roles { get; set; }
  映射文件类UserMap.cs:
using ponentModel.DataAnnotations.S
using System.Data.Entity.ModelC
using Portal.E
namespace Portal.Mapping
public class UserMap : EntityTypeConfiguration&User&
public UserMap()
// Primary Key
this.HasKey(t =& t.UserID);
// Properties
this.Property(t =& t.UserName)
.HasMaxLength(50);
this.Property(t =& t.Password)
.HasMaxLength(100);
// Table & Column Mappings
this.ToTable("User");
this.Property(t =& t.UserID).HasColumnName("UserID");
this.Property(t =& t.UserName).HasColumnName("UserName");
this.Property(t =& t.Password).HasColumnName("Password");
this.Property(t =& t.IsValid).HasColumnName("IsValid");
  文件类Role.cs:
using System.Collections.G
namespace Portal.Entities
public partial class Role
public int RoleID { get; set; }
public string RoleName { get; set; }
public virtual ICollection&User& Users { get; set; }
  映射文件类RoleMap.cs:
using ponentModel.DataAnnotations.S
using System.Data.Entity.ModelC
using Portal.E
namespace Portal.Mapping
public class RoleMap : EntityTypeConfiguration&Role&
public RoleMap()
// Primary Key
this.HasKey(t =& t.RoleID);
// Properties
this.Property(t =& t.RoleName)
.HasMaxLength(50);
// Table & Column Mappings
this.ToTable("Role");
this.Property(t =& t.RoleID).HasColumnName("RoleID");
this.Property(t =& t.RoleName).HasColumnName("RoleName");
// Relationships
this.HasMany(t =& t.Users)
.WithMany(t =& t.Roles)
m.ToTable("UserRole");
m.MapLeftKey("RoleID");
m.MapRightKey("UserID");
  运行之后生成的表结构:
  5、一对多自反关系
  一对多自反关系,即一个表存在一个外键列引用自身的主键。在项目中,最常见的一对多自反关系为分类表,分类表通过一个ParentID列保存引用主键,已实现无限级递归。
  Fluent API实现方式:
  文件类Category.cs:
using System.Collections.G
namespace Portal.Entities
public class Category
public int CategoryID { get; set; }
public int CategoryNo { get; set; }
public string CategoryName { get; set; }
public Nullable&int& ParentID { get; set; }
public virtual Category Parent { get; set; }
public virtual ICollection&Category& Children { get; set; }
  映射文件类CategoryMap.cs:
using ponentModel.DataAnnotations.S
using System.Data.Entity.ModelC
using Portal.E
namespace Portal.Mapping
public class CategoryMap : EntityTypeConfiguration&Category&
public CategoryMap()
// Primary Key
this.HasKey(t =& t.CategoryID);
// Properties
this.Property(t =& t.CategoryName)
.IsRequired()
.HasMaxLength(50);
// Table & Column Mappings
this.ToTable("Category");
this.Property(t =& t.CategoryID).HasColumnName("CategoryID");
this.Property(t =& t.CategoryNo).HasColumnName("CategoryNo");
this.Property(t =& t.CategoryName).HasColumnName("CategoryName");
this.Property(t =& t.ParentID).HasColumnName("ParentID");
// Relationships
this.HasOptional(t =& t.Parent)
.WithMany(t =& t.Children)
.HasForeignKey(d =& d.ParentID);
  以上代码在运行之后,生成的数据表:
  6、多对多自反关系
  多对多关系示例:Family中一条记录可能有多个Parents,也可能有多个Children。
  文件类Family.cs:
using System.Collections.G
namespace Portal.Entities
/// &summary&
/// Family表多对多自反关系
/// &/summary&
public partial class Family
public Family()
this.Parents = new List&Family&();
this.Children = new List&Family&();
public int FamilyID { get; set; }
public string Name { get; set; }
public Nullable&bool& Sex { get; set; }
public Nullable&System.DateTime& Birthday { get; set; }
public virtual ICollection&Family& Parents { get; set; }
public virtual ICollection&Family& Children { get; set; }
  映射文件类FamilyMap.cs:
using ponentModel.DataAnnotations.S
using System.Data.Entity.ModelC
using Portal.E
namespace Portal.Mapping
public class FamilyMap : EntityTypeConfiguration&Family&
public FamilyMap()
// Primary Key
this.HasKey(t =& t.FamilyID);
// Properties
this.Property(t =& t.Name)
.HasMaxLength(50);
// Table & Column Mappings
this.ToTable("Family");
this.Property(t =& t.FamilyID).HasColumnName("FamilyID");
this.Property(t =& t.Name).HasColumnName("Name");
this.Property(t =& t.Sex).HasColumnName("Sex");
this.Property(t =& t.Birthday).HasColumnName("Birthday");
// Relationships
this.HasMany(t =& t.Parents)
.WithMany(t =& t.Children)
m.ToTable("FamilyRelationship");
m.MapLeftKey("ParentID");
m.MapRightKey("ChildID");
  Family类及映射配置类,在运行之后生成的数据表结构:
  在上面的表结构中,指定Family之间的中介表为FamilyRelationship,其中FamilyRelationship的两个字段ParentID及ChildID均引用Familyi表中的FamilyID作为外键。可能在实际的项目过程中,出现这种多对多自反引用关系的情况比较少见。
(1)我们在进行SSH开发大※的项目的时候,使用myeclipse自带的hibernate的逆向工程工具时,发现竟然无法生成one-to-one
one-to-many等的主外键关系,明明的数据库建时已经有主外键关系了.为啥逆向生成时就不行了呢? (2)首先说一下,我使用的是PHP开发环境Appserv自带的MySQL数据库,不是单独安装的: (3)这是因 ...
以前在接触数据库的时候,理论知识也没有学习过,做时是直接去做些简单的操作,后来看了&数据库系统原理&这本书,那个艰深晦涩就不说了,看了几遍之后,终于有些明白.时隔一年多结合现在正在做的再去翻看的时候,明了许多. 下图是主外键的区别:
主键使用原则:
1.应当是对用户没有意义的
本节导航 1.补充 2.添加对电影的查询 3.添加导演表.创建导演表和电影表的主外键关系 4.Model属性应用 5.持久对象的生命周期
下载视频 一.补充 1.EF对主键的处理 我们在上一节中的Movie实体中并没有设置ID列为主键列,但是在数据表创建完成之后我们看到ID列成为了主键.这是因为EF会对实体类中ID进行检索,对 ...
--建立主外键关系 EL_PickListTable中的RecId --做EL_PickListLine中的外键 别名PickListTableRecId --on update cascade on delete cascade 级联删除.更新,当主键表中 --有相关变动的时候 外键表跟着变化 alter table El_PickListLine add ...
/查询表之间的主外键关系/Select b.table_name 主键表名,
b.column_name 主键列名,
a.table_name 外键表名,
a.column_name 外键列名From (Select a.constraint_name,

我要回帖

更多关于 ef带外键表的新增 的文章

 

随机推荐