假設咱們在程序中要用到的類的結構是這樣的,這裏比較特別的是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; } }