Entity Framework的問題在於它想要的是一個非常緊密的關係實體之間,它確實如此。如果你說'Toy
:你可以擁有任何Animal
作爲所有者,但只有一些Animal
類型會讓你成爲一個孩子',那麼實體框架讀取,因爲'我不能讓Toy
暗含地參考Animal
,因爲Animal
什麼也不知道約Toy
和Toy
實際上與Cat
或Dog
有關。
解決這個問題的最簡單的方法就是讓Pet
一類Toys
,然後進行Cat
和Dog
繼承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
表我們的對象(Dog
和Cat
不再是數據庫實體):
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);
當我們添加一個名爲Cat
Frank
,我們得到:
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);
然後,我們可以將更多的屬性爲Pet
或PetAttributes
,並創造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 也使得難以在類型錯誤的關係中犯錯。
答案將取決於您計劃如何映射繼承。你是否也想映射基類'Animal',或者你想讓EF忽略它,這樣每個子類型都將擁有自己的獨立映射? –
@GertArnold基類和派生類已經映射。我想我應該將Animal標記爲抽象。但是,動物是EF意識到的實體。 –