2017-02-03 130 views
2

如何將DogsCats映射到Toys而不是Rats,因爲它們不是寵物?如何將具有實體集合的派生類映射到實體框架

public abstract class Animal { 
    public int Id { get; set; } 
} 

public class Cat : Animal { 
    public virtual ICollection<Toy> Toys { get; set; } 
} 

public class Dog : Animal { 
    public virtual ICollection<Toy> Toys { get; set; } 
} 

public class Rat : Animal { 

} 

public class Toy { 
    public int Id { get; set; } 

    public string Name { get; set; } 

    public Animal Owner { get; set; } 

    public int OwnerId { get; set; } 
} 

我試過,用流利的映射,這樣做的:

public class CatEntityConfiguration : EntityConfiguration<Cat> { 
    public CatEntityConfiguration() { 
     HasMany(c => c.Toys).WithRequired(t => t.Owner); 
    } 
} 

Owner必須是Cat類型,而不是Animal的,但隨後的過程中,Dog希望OwnerDog型的,不AnimalCat。我能在Toy一個DogCat屬性,但是這似乎是一個黑客,而不是解決方案。

+0

答案將取決於您計劃如何映射繼承。你是否也想映射基類'Animal',或者你想讓EF忽略它,這樣每個子類型都將擁有自己的獨立映射? –

+0

@GertArnold基類和派生類已經映射。我想我應該將Animal標記爲抽象。但是,動物是EF意識到的實體。 –

回答

5

Entity Framework的問題在於它想要的是一個非常緊密的關係實體之間,它確實如此。如果你說'Toy:你可以擁有任何Animal作爲所有者,但只有一些Animal類型會讓你成爲一個孩子',那麼實體框架讀取,因爲'我不能讓Toy暗含地參考Animal ,因爲Animal什麼也不知道ToyToy實際上與CatDog有關。

解決這個問題的最簡單的方法就是讓Pet一類Toys,然後進行CatDog繼承Pet類,其中Rat仍然是一個Animal

public abstract class Animal 
{ 
    public int Id { get; set; } 
} 

public abstract class Pet : Animal 
{ 
    public virtual ICollection<Toy> Toys { get; set; } 
} 

public class Cat : Pet 
{ 
    public string Name { get; set; } 
} 

public class Dog : Pet 
{ 
    public int CollarColor { get; set; } 
} 

public class Rat : Animal 
{ 

} 

public class Toy 
{ 
    public int Id { get; set; } 
    public Pet Owner { get; set; } 
} 

EF然後將創建一個Pets表我們的對象(DogCat不再是數據庫實體):

CREATE TABLE [dbo].[Pets] (
    [Id]   INT   IDENTITY (1, 1) NOT NULL, 
    [Discriminator] NVARCHAR (128) NOT NULL, 
    [Name]   NVARCHAR (MAX) NULL, 
    [CollarColor] INT   NULL, 
    CONSTRAINT [PK_dbo.Pets] PRIMARY KEY CLUSTERED ([Id] ASC) 
); 

CreateTable(
    "dbo.Pets", 
    c => new 
     { 
      Id = c.Int(nullable: false, identity: true), 
      Discriminator = c.String(nullable: false, maxLength: 128), 
      Name = c.String(), 
      CollarColor = c.Int(), 
     }) 
    .PrimaryKey(t => t.Id); 

當我們添加一個名爲CatFrank,我們得到:

Id Discriminator Name CollarColor 
1 Cat    Frank NULL 

如果你不喜歡這個DB結構,另一個選擇是創建一個PetAttributes類的其中每個Pet獲得一個,然後Toys是該類的一部分,每個玩具歸PetAttribute擁有,然後生活繼續。唯一的問題是你的導航變成了Cat.Attributes.Toys,但你可以建立一個get-只有財產來解決這個問題。

爲了擺脫Discriminator列,我們還可以添加:

modelBuilder.Ignore<Pet>(); 

那麼這建立一個新的,但仍非最佳DB結構:

CreateTable(
    "dbo.Toys", 
    c => new 
     { 
      Id = c.Int(nullable: false, identity: true), 
      Cat_Id = c.Int(), 
      Dog_Id = c.Int(), 
     }) 
    .PrimaryKey(t => t.Id) 
    .ForeignKey("dbo.Cats", t => t.Cat_Id) 
    .ForeignKey("dbo.Dogs", t => t.Dog_Id) 
    .Index(t => t.Cat_Id) 
    .Index(t => t.Dog_Id); 

所以,最後一個也是最後一個選項,用Toys創建一個PetAttributes類:

public abstract class Pet : Animal 
{ 
    public PetAttributes Attributes { get; set; } 
} 

public class PetAttributes 
{ 
    [Key] 
    public int OwnerId { get; set; } 

    [ForeignKey(nameof(OwnerId))] 
    public Pet Owner { get; set; } 

    public virtual ICollection<Toy> Toys { get; set; } 
} 

public class Toy 
{ 
    public int Id { get; set; } 
    public PetAttributes Owner { get; set; } 
} 

我們覆蓋OnModelCreating

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    base.OnModelCreating(modelBuilder); 

    modelBuilder.Ignore<Pet>(); 
    modelBuilder.Entity<Pet>().HasRequired(p => p.Attributes).WithRequiredDependent(a => a.Owner); 
} 

,我們得到一個新的表結構:

CreateTable(
    "dbo.Cats", 
    c => new 
     { 
      Id = c.Int(nullable: false, identity: true), 
      Name = c.String(), 
      Attributes_OwnerId = c.Int(), 
     }) 
    .PrimaryKey(t => t.Id) 
    .ForeignKey("dbo.PetAttributes", t => t.Attributes_OwnerId) 
    .Index(t => t.Attributes_OwnerId); 

CreateTable(
    "dbo.PetAttributes", 
    c => new 
     { 
      OwnerId = c.Int(nullable: false, identity: true), 
     }) 
    .PrimaryKey(t => t.OwnerId); 

CreateTable(
    "dbo.Toys", 
    c => new 
     { 
      Id = c.Int(nullable: false, identity: true), 
      Owner_OwnerId = c.Int(), 
     }) 
    .PrimaryKey(t => t.Id) 
    .ForeignKey("dbo.PetAttributes", t => t.Owner_OwnerId) 
    .Index(t => t.Owner_OwnerId); 

然後,我們可以將更多的屬性爲PetPetAttributes,並創造get - 只有屬於他們的房產PetAttributes

public abstract class Pet : Animal 
{ 
    public string Name { get; set; } 

    public PetAttributes Attributes { get; set; } 

    public ICollection<Toy> Toys => Attributes.Toys; 
} 
CreateTable(
    "dbo.Cats", 
    c => new 
     { 
      Id = c.Int(nullable: false, identity: true), 
      Name = c.String(), 
      Attributes_OwnerId = c.Int(), 
     }) 
    .PrimaryKey(t => t.Id) 
    .ForeignKey("dbo.PetAttributes", t => t.Attributes_OwnerId) 
    .Index(t => t.Attributes_OwnerId); 

CreateTable(
    "dbo.Dogs", 
    c => new 
     { 
      Id = c.Int(nullable: false, identity: true), 
      CollarColor = c.Int(nullable: false), 
      Name = c.String(), 
      Attributes_OwnerId = c.Int(), 
     }) 
    .PrimaryKey(t => t.Id) 
    .ForeignKey("dbo.PetAttributes", t => t.Attributes_OwnerId) 
    .Index(t => t.Attributes_OwnerId); 

正如我們所看到的,EF使得困難,但不是不可能一個實體映射爲多個其他實體關係的許多部分。這主要是由於類型限制:EF 使得難以在類型錯誤的關係中犯錯。