假设咱们在程序中要用到的类的结构是这样的,这里比较特别的是B在A中出现了最少两次html
public class B { [Key] public int Id { get; set; } public string Name { get; set; } } public class A { [Key] public int Id { get; set; } public string Name { get; set; } public B B1 { get; set; } /*第一次*/ public B B2 { get; set; } /*第二次*/ }
那咱们如何经过EF框架映射到数据库中呢?数据库
若是是下面这种方式就会很是简单,使用框架
public class B { [Key] public int Id { get; set; } public string Name { get; set; } } public class A { [Key] public int Id { get; set; } public string Name { get; set; } public B B1 { get; set; } /*第一次*/ }
Code First 指定外键名称中的任何方法均可以实现ide
-------------------------------------------------------------------------------------------函数
接下来将我使用过程当中遇到的错误方法和正确方法都罗列出来测试
错误方法一:[ForeignKey("F_UserID")]注释 看代码spa
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Data.Entity; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication1 { class Program { static void Main( string[] args ) { using (var db = new MyTestContent()) { db.A.Add(new A { Name = "A", B1 = new B { Name = "B1" }, B2 = new B { Name = "B2" } }); db.SaveChanges(); A a = db.A.FirstOrDefault(); } } public class A { [Key] public int Id { get; set; } public string Name { get; set; } public int BId1 { get; set; } [ForeignKey("BId1")] public B B1 { get; set; } public int BId2 { get; set; } [ForeignKey("BId2")] public B B2 { get; set; } } public class B { [Key] public int Id { get; set; } public string Name { get; set; } } public class MyTestContent : DbContext { public MyTestContent( ) { Database.SetInitializer<MyTestContent>(null); } public DbSet<B> B { get; set; } public DbSet<A> A { get; set; } } } }
执行add-migratiton createDB生成以下DbMigrationcode
namespace EFLoading.Migrations { using System; using System.Data.Entity.Migrations; public partial class createDB : DbMigration { public override void Up() { CreateTable( "dbo.A", c => new { Id = c.Int(nullable: false, identity: true), Name = c.String(), BId1 = c.Int(nullable: false), BId2 = c.Int(nullable: false), }) .PrimaryKey(t => t.Id) .ForeignKey("dbo.B", t => t.BId1, cascadeDelete: true) .ForeignKey("dbo.B", t => t.BId2, cascadeDelete: true) .Index(t => t.BId1) .Index(t => t.BId2); CreateTable( "dbo.B", c => new { Id = c.Int(nullable: false, identity: true), Name = c.String(), }) .PrimaryKey(t => t.Id); } public override void Down() { DropForeignKey("dbo.A", "BId2", "dbo.B"); DropForeignKey("dbo.A", "BId1", "dbo.B"); DropIndex("dbo.A", new[] { "BId2" }); DropIndex("dbo.A", new[] { "BId1" }); DropTable("dbo.B"); DropTable("dbo.A"); } } }
在程序包管理器控制台中执行:Update-Database –Verbost,会出现这样的错误htm
Introducing FOREIGN KEY constraint 'FK_dbo.A_dbo.B_BId2' on table 'A' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint. See previous errors.blog
也就是说连数据库都没办法建立成功, 从字面意思上说可能这种方式须要在数据库中取消级联删除和更新功能,而后级联删除和更新须要代码操做来完成。
错误缘由:不明确
错误方法二:[Column("BId1")]注释 看代码
按照错误一的方法操做,只是将类A的代码改成下方的样子
public class A { [Key] public int Id { get; set; } public string Name { get; set; } [Column("BId1")] public int BId1 { get; set; } public virtual B B1 { get; set; } [Column("BId2")] public int BId2 { get; set; } public virtual B B2 { get; set; } }
错误方式同方法一:数据库建立失败
正确(可行)的方法:
依赖EF框架自动生成外键, 咱们只须要指定导航属性便可,EF自动建立命名规则为:“表名_主键名”的复键
代码奉上
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Data.Entity; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EFLoading { class Program { static void Main(string[] args) { using (var ctx = new EFLoadingContext()) { A InsertA = new A { Name = "A", B1 = new B { Name = "B1" }, B2 = new B { Name = "B2" } }; ctx.A.Add(InsertA); ctx.SaveChanges(); A readA = ctx.A.FirstOrDefault(); } } } public class A { [Key] public int Id { get; set; } public string Name { get; set; } public virtual B B1 { get; set; } public virtual B B2 { get; set; } } public class B { [Key] public int Id { get; set; } public string Name { get; set; } } public class EFLoadingContext : DbContext { public EFLoadingContext( ) { Database.SetInitializer<EFLoadingContext>(null); } public DbSet<A> A { get; set; } public DbSet<B> B { get; set; } } }
执行add-migration createDB命令后生成的DbMigration的代码
namespace EFLoading.Migrations { using System; using System.Data.Entity.Migrations; public partial class createDB : DbMigration { public override void Up() { CreateTable( "dbo.A", c => new { Id = c.Int(nullable: false, identity: true), Name = c.String(), B1_Id = c.Int(), B2_Id = c.Int(), }) .PrimaryKey(t => t.Id) .ForeignKey("dbo.B", t => t.B1_Id) .ForeignKey("dbo.B", t => t.B2_Id) .Index(t => t.B1_Id) .Index(t => t.B2_Id); CreateTable( "dbo.B", c => new { Id = c.Int(nullable: false, identity: true), Name = c.String(), }) .PrimaryKey(t => t.Id); } public override void Down() { DropForeignKey("dbo.A", "B2_Id", "dbo.B"); DropForeignKey("dbo.A", "B1_Id", "dbo.B"); DropIndex("dbo.A", new[] { "B2_Id" }); DropIndex("dbo.A", new[] { "B1_Id" }); DropTable("dbo.B"); DropTable("dbo.A"); } } }
Update-Database -Verbose
命令数据库建立成功 数据库结构以下
级联更新成功了
一样方法测试级联删除也成功了
须要特别注意的地方
在A类的构造函数中不能包含B1 B2的new函数,好比下面的就会没法级联更新(更新后值都被清空了) ,下面是错误的 错误的 错误的
public class A { public A( ) { B1 = new B { }; B2 = new B { }; } [Key] public int Id { get; set; } public string Name { get; set; } public virtual B B1 { get; set; } public virtual B B2 { get; set; } }