我知道关于这个问题有很多问题,但我找不到能够解释如何解决我的特定问题的问题。我认为这意味着它可能是不可解的(我认为它可能是'向后'到EF的思维方式),但我不得不问。
我有一个模型,其中包含三个(缩写)POCO:
[Table("People")]
public class Person {
public int PersonID { get; set; }
[Required]
public string PersonName { get; set; }
}
public class Location {
public int LocationID { get; set; }
public int LocationTypeID { get; set; }
public virtual LocationType LocationType { get; set; }
}
public class Van : Location {
public int PartyID { get; set; }
public virtual Party Party { get; set; }
}
这些由(缩写的)数据库表支持(我们手工编写):
CREATE TABLE People (
PersonID INTEGER IDENTITY NOT NULL,
PersonName VARCHAR(255) NOT NULL,
PRIMARY KEY (PersonID)
)
CREATE TABLE Locations (
LocationID INTEGER IDENTITY NOT NULL,
LocationTypeID INTEGER NOT NULL,
FOREIGN KEY (LocationTypeID) REFERENCES LocationTypes(LocationTypeID)
)
CREATE TABLE Vans (
LocationID INTEGER NOT NULL,
PersonID INTEGER NOT NULL,
PRIMARY KEY (LocationID),
FOREIGN KEY (LocationID) REFERENCES Locations(LocationID),
FOREIGN KEY (PersonID) REFERENCES People(PersonID)
)
您可以想象LocationTypes
的样子。
Locations
是每个类型的表层次结构的根 - 还有适当的检查约束来强制执行此操作。 Vans
是一种位置,其他与此类无关的内容如Warehouse
。
现在,Van
属于Person
,因为我们向员工发放面包车,他们有责任填写燃料,而不是崩溃,将其带到客户站点,当他们用尽所有螺丝,钻头和铠装直流电缆时,他们会订购更多东西。但是,并非每个Person
都有一个面包车(其中一些面包车在一辆面包车中成对使用),Person
表没有指向Van
的外键 - 它是另一种方式。这在某种程度上是一次历史性事故,但它对情况进行了非常巧妙的模拟,因为虽然Person
不需要Van
,但Van
最确定必须有一个人
所以我的问题是:如何让Person
拥有一个带有Van
的导航属性?
public virtual Van Van { get; set; }
我已经做了大量的数据注释和流畅的API,而我最接近的是OnModelCreating
:
modelBuilder.Entity<Van>()
.HasRequired(v => v.Person)
.WithOptional(p => p.Van);
不幸的是,这会尝试使用生成Van
对象的代理填充Location
属性。它甚至可能是正确的Location
对象(我无法检查),但它没有意识到应该寻找面包车。但是,我确实怀疑它在查找时可能会尝试将PersonID
与LocationID
匹配 - 如果没有Fluent API映射,我根本就没有任何面包车,这就是我的意思expect(所有PersonID
值都低于对应于vans的最低LocationID
值,因此无法找到任何内容。
如果Person
具有Van
的可空外键,这无疑会非常容易,但是我们在两个方向上都有外键,如果我们从{{{{}}中取出一个外键1}}然后我们不会对Van
有Van
的绝对必要约束进行建模。
所以,我想,Person
拥有这种关系,而Van
上的Van
属性是一个反向导航属性,但似乎EF并不是很擅长这种关系一对一的技巧,即使一端是可选的。有没有办法让它发挥作用,还是我必须接受妥协?
为了Entity Framework的缺失功能,我们通常拒绝妥协数据库模型。我真正需要的是告诉EF可以通过加入Vans.PersonID = Person.PersonID上的Vans来填充Person
上的Van
属性。
答案 0 :(得分:4)
问题在于目前不支持此功能。你提到你没有找到任何问题解决你的问题。我想知道你是否发现任何问题,提到EF不支持解决这种一对一关系所必需的唯一约束/候选键。
在数据库中,只有依赖表中的FK是唯一的,才能实现一对一的关系。这可以通过两种方式完成:在依赖表中的FK列上放置唯一约束(索引),或者在从属表中将PK用作FK到主表。
EF对参照完整性实施与数据库相同的规则,但在一对一关系和缺乏对唯一约束的支持的情况下,它不支持前一种方式。 EF只能通过将依赖表的PK作为FK到主表来建模一对一关系。
您可以在Data UserVoice上投票支持唯一约束/候选键。
如何解决您的特定问题?通过欺骗EF。让EF认为您具有一对多关系,并在PersonID
表中的Van
上设置唯一约束。比这更新你的人:
[Table("People")]
public class Person {
public int PersonID { get; set; }
[Required]
public string PersonName { get; set; }
public virtual ICollection<Van> Vans { get; set; }
[NotMapped]
public Van Van
{
get { return Vans.FirstOrDefault(); }
set
{
Vans.Clear();
if (value != null)
{
Vans.Add(value);
}
}
}
}
这是一个非常丑陋的解决方法,因为Vans
集合仍然是公开的。您可以发挥其可见性,但要确保您了解一些事情: