【文章內(nèi)容簡(jiǎn)介】
(().().Name + 保存失敗)。 } ()。 }運(yùn)行結(jié)果同樣是保存失敗,說(shuō)明我們的并發(fā)控制起作用了。分析一下EF執(zhí)行的SQL:exec sp_executesql N39。update [dbo].[People]set [SocialSecurityNumber] = @0where (([PersonId] = @1) and ([SocialSecurityNumber] = @2))39。,N39。@0 int,@1 int,@2 int39。,@0=123,@1=1,@2=12345678可以看到,EF將我們要并發(fā)控制的列SocialSecurityNumber也作為一個(gè)篩選條件,這樣firContext保存的時(shí)候也會(huì)因?yàn)榈臄?shù)據(jù)庫(kù)中SocialSecurityNumber值變了,取不到對(duì)應(yīng)的記錄而更新失敗。補(bǔ)充一下:如果是EDMX如何將字段設(shè)置為Concurrency。很簡(jiǎn)單,在對(duì)應(yīng)的字段上右鍵屬性。在打開(kāi)的屬性窗口中有一個(gè)并發(fā)模式,你將它選擇為Fixed即可。EF Code First 學(xué)習(xí)筆記:關(guān)系 一對(duì)多關(guān)系項(xiàng)目中最常用到的就是一對(duì)多關(guān)系了。Code First對(duì)一對(duì)多關(guān)系也有著很好的支持。很多情況下我們都不需要特意的去配置,Code First就能通過(guò)一些引用屬性、導(dǎo)航屬性等檢測(cè)到模型之間的關(guān)系,自動(dòng)為我們生成外鍵。觀察下面的類:View Code public class Destination { public int DestinationId { get。 set。 } public string Name { get。 set。 } public string Country { get。 set。 } public string Description { get。 set。 } public byte[] Photo { get。 set。 } public ListLodging Lodgings { get。 set。 } } public class Lodging { public int LodgingId { get。 set。 } public string Name { get。 set。 } public string Owner { get。 set。 } public bool IsResort { get。 set。 } public decimal MilesFromNearestAirport { get。 set。 } public Destination Destination { get。 set。 } }Code First觀察到Lodging類中有一個(gè)對(duì)Destination的引用屬性,同時(shí)Destination中又有一個(gè)集合導(dǎo)航屬性Lodgings,因此推測(cè)出Destination與Lodging的關(guān)系是一對(duì)多關(guān)系,所以在生成的數(shù)據(jù)庫(kù)中為自動(dòng)為L(zhǎng)odging表生成外鍵:其實(shí),只要在一個(gè)類中存在引用屬性,即:View Code public class Destination { public int DestinationId { get。 set。 } public string Name { get。 set。 } public string Country { get。 set。 } public string Description { get。 set。 } public byte[] Photo { get。 set。 } } public class Lodging { public int LodgingId { get。 set。 } public string Name { get。 set。 } public string Owner { get。 set。 } public bool IsResort { get。 set。 } public decimal MilesFromNearestAirport { get。 set。 } public Destination Destination { get。 set。 } } 或一另一個(gè)類中存在導(dǎo)航屬性:View Code public class Destination { public int DestinationId { get。 set。 } public string Name { get。 set。 } public string Country { get。 set。 } public string Description { get。 set。 } public byte[] Photo { get。 set。 } public ListLodging Lodgings { get。 set。 } } public class Lodging { public int LodgingId { get。 set。 } public string Name { get。 set。 } public string Owner { get。 set。 } public bool IsResort { get。 set。 } public decimal MilesFromNearestAirport { get。 set。 } } Code First都能檢測(cè)到它們之間一對(duì)多的關(guān)系,自動(dòng)生成外鍵。指定外鍵當(dāng)然我們也可以自己在類中增加一個(gè)外鍵。默認(rèn)情況下,如果你的外鍵命名是規(guī)范的話,Code First會(huì)將的該屬性設(shè)置為外鍵,不再自動(dòng)創(chuàng)建一個(gè)外鍵,如:View Code public class Destination { public int DestinationId { get。 set。 } public string Name { get。 set。 } public string Country { get。 set。 } public string Description { get。 set。 } public byte[] Photo { get。 set。 } public ListLodging Lodgings { get。 set。 } } public class Lodging { public int LodgingId { get。 set。 } public string Name { get。 set。 } public string Owner { get。 set。 } public bool IsResort { get。 set。 } public decimal MilesFromNearestAirport { get。 set。 } //外鍵 public int TargetDestinationId { get。 set。 } public Destination Target { get。 set。 } } 規(guī)范命名是指符合:命名為“[目標(biāo)類型的鍵名],[目標(biāo)類型名稱]+[目標(biāo)類型鍵名稱]”,或“[導(dǎo)航屬性名稱]+[目標(biāo)類型鍵名稱]”的形式,在這里目標(biāo)類型就是Destination,相對(duì)應(yīng)的命名就是:DestinationId,DestinationDestinationId,TargetDestinationId對(duì)于命名不規(guī)范的列,Code First會(huì)怎做呢?比如我們將外鍵改為:public int TarDestinationId { get。 set。 }再重新生成數(shù)據(jù)庫(kù):可以看到Code First沒(méi)有識(shí)別到TarDestinationId是一個(gè)外鍵,于是自己創(chuàng)建了一個(gè)外鍵:Target_DestinationId。這時(shí)我們要告訴Code First該屬性是一個(gè)外鍵。使用Data Annotations指定外鍵: [ForeignKey(Target)] public int TarDestinationId { get。 set。 } public Destination Target { get。 set。 }或 public int TarDestinationId { get。 set。 } [ForeignKey(TarDestinationId)] public Destination Target { get。 set。 }注意ForeignKey位置的不同,其后帶的參數(shù)也不同。這樣,生成的數(shù)據(jù)庫(kù)就是我們所期望的了。Code First沒(méi)有再生成別的外鍵。用Fluent API指定外鍵:Lodging().HasRequired(p = ).WithMany(l = ).HasForeignKey(p = )。對(duì)同一個(gè)實(shí)體多個(gè)引用的情況我們來(lái)考慮一下下面的情況:View Code public class Lodging { public int LodgingId { get。 set。 } public string Name { get。 set。 } public string Owner { get。 set。 } public bool IsResort { get。 set。 } public decimal MilesFromNearestAirport { get。 set。 } public Destination Target { get。 set。 } //第一聯(lián)系人 public Person PrimaryContact { get。 set。 } //第二聯(lián)系人 public Person SecondaryContact { get。 set。 } } public class Person { public int PersonID { get。 set。 } public string FirstName { get。 set。 } public string LastName { get。 set。 } public ListLodging PrimaryContactFor { get。 set。 } public ListLodging SecondaryContactFor { get。 set。 } }Lodging(旅店)有兩個(gè)對(duì)Person表的引用,分別是PrimaryContact與SecondaryContact,同時(shí),在Person表中也有對(duì)這兩個(gè)聯(lián)系人的導(dǎo)航:PrimaryContactFor與SecondaryContactFor??纯碈ode First默認(rèn)會(huì)生成怎樣的數(shù)據(jù)庫(kù)天哪,竟然生成了四個(gè)外鍵。因?yàn)橛袃商最愋鸵粯拥膶?dǎo)航屬性與引用屬性,Code First無(wú)法確定它們之間的對(duì)應(yīng)關(guān)系,就單獨(dú)為每個(gè)屬性都創(chuàng)建了一個(gè)關(guān)系。這肯定不是我們所期望的,為了讓Code First知道它們之間的對(duì)應(yīng)關(guān)系,在這里要用到逆導(dǎo)航屬性來(lái)解決。使用Data Annotations: //第一聯(lián)系人 [InverseProperty(PrimaryContactFor)] public Person PrimaryContact { get。 set。 } //第二聯(lián)系人 [InverseProperty(SecondaryContactFor)] public Person SecondaryContact { get。 set。 } 或使用Fluent API: Lodging().HasOptional(l = ).WithMany(p = )。 Lodging().HasOptional(l=).WithMany(p=)。再重新生成數(shù)據(jù)庫(kù),結(jié)果如圖:多對(duì)多關(guān)系如果有兩個(gè)類中,各自都是導(dǎo)航屬性指向另一個(gè)類,Code First會(huì)認(rèn)為這兩個(gè)類之間是多對(duì)多關(guān)系,例如:View Code public class Acti