小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

EF Code First 學(xué)習(xí)筆記:關(guān)系

 ThinkTank_引擎 2014-04-07

一對(duì)多關(guān)系

項(xiàng)目中最常用到的就是一對(duì)多關(guān)系了。Code First對(duì)一對(duì)多關(guān)系也有著很好的支持。很多情況下我們都不需要特意的去配置,Code First就能通過一些引用屬性、導(dǎo)航屬性等檢測(cè)到模型之間的關(guān)系,自動(dòng)為我們生成外鍵。觀察下面的類:

復(fù)制代碼
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 List<Lodging> 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; }
    }
復(fù)制代碼

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è)類中存在引用屬性,即:

復(fù)制代碼
 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; }
    } 
復(fù)制代碼

或一另一個(gè)類中存在導(dǎo)航屬性:

復(fù)制代碼
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 List<Lodging> 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; }
    } 
復(fù)制代碼

Code First都能檢測(cè)到它們之間一對(duì)多的關(guān)系,自動(dòng)生成外鍵。

 指定外鍵

當(dāng)然我們也可以自己在類中增加一個(gè)外鍵。默認(rèn)情況下,如果你的外鍵命名是規(guī)范的話,Code First會(huì)將的該屬性設(shè)置為外鍵,不再自動(dòng)創(chuàng)建一個(gè)外鍵,如:

復(fù)制代碼
 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 List<Lodging> 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; }
    } 
復(fù)制代碼

規(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沒有識(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沒有再生成別的外鍵。

用Fluent API指定外鍵:

modelBuilder.Entity<Lodging>().HasRequired(p => p.Target).WithMany(l => l.Lodgings).HasForeignKey(p => p.TarDestinationId);

對(duì)同一個(gè)實(shí)體多個(gè)引用的情況

我們來考慮一下下面的情況:

復(fù)制代碼
 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 List<Lodging> PrimaryContactFor { get; set; }
        public List<Lodging> SecondaryContactFor { get; set; } 
    }
復(fù)制代碼

Lodging(旅店)有兩個(gè)對(duì)Person表的引用,分別是PrimaryContact與SecondaryContact,同時(shí),在Person表中也有對(duì)這兩個(gè)聯(lián)系人的導(dǎo)航:PrimaryContactFor與SecondaryContactFor。

看看Code First默認(rèn)會(huì)生成怎樣的數(shù)據(jù)庫(kù)

天哪,竟然生成了四個(gè)外鍵。因?yàn)橛袃商最愋鸵粯拥膶?dǎo)航屬性與引用屬性,Code First無法確定它們之間的對(duì)應(yīng)關(guān)系,就單獨(dú)為每個(gè)屬性都創(chuàng)建了一個(gè)關(guān)系。這肯定不是我們所期望的,為了讓Code First知道它們之間的對(duì)應(yīng)關(guān)系,在這里要用到逆導(dǎo)航屬性來解決。

使用Data Annotations:

       //第一聯(lián)系人
        [InverseProperty("PrimaryContactFor")] 
        public Person PrimaryContact { get; set; }
        //第二聯(lián)系人
        [InverseProperty("SecondaryContactFor")] 
        public Person SecondaryContact { get; set; } 

或使用Fluent API:

 modelBuilder.Entity<Lodging>().HasOptional(l => l.PrimaryContact).WithMany(p => p.PrimaryContactFor);
modelBuilder.Entity<Lodging>().HasOptional(l=>l.SecondaryContact).WithMany(p=>p.SecondaryContactFor);

再重新生成數(shù)據(jù)庫(kù),結(jié)果如圖:

多對(duì)多關(guān)系

如果有兩個(gè)類中,各自都是導(dǎo)航屬性指向另一個(gè)類,Code First會(huì)認(rèn)為這兩個(gè)類之間是多對(duì)多關(guān)系,例如:

復(fù)制代碼
  public class Activity
     {
         public int ActivityId { get; set; }
         [Required, MaxLength(50)] 
         public string Name { get; set; } 
         public List<Trip> Trips { get; set; }
     }

    public class Trip
    {
        public int TripId{get;set;}
        public DateTime StartDate{get;set;}
        public DateTime EndDate { get; set; }
        public decimal CostUSD { get; set; }
        public byte[] RowVersion { get; set; }
        public List<Activity> Activities { get; set; }
    }
復(fù)制代碼

一個(gè)Trip類可以有一些Activites日程,而一個(gè)Activity日程又可以計(jì)劃好幾個(gè)trips(行程),顯然它們之間是多對(duì)多的關(guān)系。我們看看默認(rèn)生成的數(shù)據(jù)庫(kù)是怎么樣的:

可以看到,Code First生成了一張中間表ActivityTrips,將另外兩張表的主鍵都作為外鍵關(guān)聯(lián)到了中間表上面。中間表中鍵的命名默認(rèn)為"[目標(biāo)類型名稱]_[目標(biāo)類型鍵名稱]".

指定表名

如果我們想指定中間表的名稱和鍵名稱,我們可以用Fluent API來配置。

modelBuilder.Entity<Trip>().HasMany(t => t.Activities).WithMany(a => a.Trips).Map(m =>
                {
                    m.ToTable("TripActivities");
                    m.MapLeftKey("TripIdentifier");//對(duì)應(yīng)Trip的主鍵
                    m.MapRightKey("ActivityId");
                });

或:

 modelBuilder.Entity<Activity>().HasMany(a => a.Trips).WithMany(t => t.Activities).Map(m =>
                {
                    m.ToTable("TripActivities");
                    m.MapLeftKey("ActivityId");//對(duì)應(yīng)Activity的主鍵
                    m.MapRightKey("TripIdentifier");
                });

一對(duì)一關(guān)系

如果我們要將兩個(gè)類配置為一對(duì)一關(guān)系,則兩個(gè)類中都要配置相應(yīng)的引用屬性,如:

復(fù)制代碼
 public class Person
    {
        public int PersonId { get; set; }
        public int SocialSecurityNumber { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        [Timestamp]
        public byte[] RowVersion { get; set; }
        public PersonPhoto Photo { get; set; }
    }

    public class PersonPhoto
    {
        [Key]
        public int PersonId { get; set; }
        public byte[] Photo { get; set; }
        public string Caption { get; set; }
        public Person PhotoOf { get; set; }
    }
復(fù)制代碼

我們?yōu)橐粋€(gè)(Person)對(duì)應(yīng)著一張相片(PersonPhoto),但如果根據(jù)這樣的模型生成數(shù)據(jù)庫(kù)為報(bào)錯(cuò):

無法確定類型“BreakAway.PersonPhoto”與“BreakAway.Person”之間的關(guān)聯(lián)的主體端。必須使用關(guān)系 Fluent API 或數(shù)據(jù)注釋顯式配置此關(guān)聯(lián)的主體端

因?yàn)镃ode First無法確認(rèn)哪個(gè)是依賴類,必須使用Fluent API或Data Annotations進(jìn)行顯示配置。

使用Data Annotations

復(fù)制代碼
public class Person
    {
        public int PersonId { get; set; }
        public int SocialSecurityNumber { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        [Timestamp]
        public byte[] RowVersion { get; set; }
        public PersonPhoto Photo { get; set; }
    }

    public class PersonPhoto
    {
        [Key, ForeignKey("PhotoOf")]
        public int PersonId { get; set; }
        public byte[] Photo { get; set; }
        public string Caption { get; set; }
        public Person PhotoOf { get; set; }
    }
復(fù)制代碼

使用Fluent API:

modelBuilder.Entity<PersonPhoto>().HasRequired(p => p.PhotoOf).WithOptional(p => p.Photo);

 注意:PersonPhoto表中的PersonId既是外鍵也必須是主鍵

 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多