我有一个带有User
和Person
实体的实体模型,这样每个实体都User
必须与 1 准确关联Person
,并且每个实体都Person
可以与零或 1 关联User
。
User (0..1) <-------> (1) Person
该关联被流畅地映射。最初我只是在Person
旁边声明:
private class PersonOrm : EntityTypeConfiguration<Person>
{
internal PersonOrm()
{
ToTable(typeof(Person).Name, DbSchemaName.People);
// has zero or one User
HasOptional(p => p.User)
.WithRequired(d => d.Person)
.Map(d => d.MapKey("PersonId"))
.WillCascadeOnDelete(false)
;
由于我遇到了这个错误,所以我也在User
旁边添加了相同的映射:
private class UserOrm : EntityTypeConfiguration<User>
{
internal UserOrm()
{
ToTable(typeof(User).Name, DbSchemaName.Identity);
// has exactly 1 Person
HasRequired(p => p.Person)
.WithOptional(d => d.User)
.Map(d => d.MapKey("PersonId"))
.WillCascadeOnDelete(false);
在应用程序中有一个场景,User
可以创建一个新的并将其与现有的Person
. 这是我目前遇到困难的地方。EF 将其视为User
关系的依赖方,并将PersonId (FK, int, not null)
列放在User
表上。我不相信可以在任一实体上使用外键属性来帮助 EF 管理关联(是吗?)。
这是一些尝试处理该场景的失败代码:
// find out if Person already exists
var person = context.People.SingleOrDefault(p => p.Emails.Any(
e => e.Value.Equals(emailAddress, StringComparison.OrdinalIgnoreCase)));
// find out if User already exists
var user = context.Users.SingleOrDefault(
u => u.Name.Equals(emailAddress, StringComparison.OrdinalIgnoreCase));
if (user == null)
{
user = new User
{
Name = emailAddress,
IsRegistered = isRegistered,
Person = person ?? PersonFactory.Create(emailAddress),
// ignore the PersonFactory.Create, that part works
};
context.Entry(user).State = EntityState.Added;
context.SaveChanges();
}
此代码在person
为 null 时工作正常(数据库中尚不存在)。但是,当person
is not null (已经存在于 db 中)并且user
为 null 时,代码会尝试创建一个新的User
并将其与现有的Person
. 调用时SaveChanges()
,我得到DbUpdateException
:
保存不为其关系公开外键属性的实体时发生错误。EntityEntries 属性将返回 null,因为无法将单个实体标识为异常源。通过在实体类型中公开外键属性,可以更轻松地在保存时处理异常。有关详细信息,请参阅 InnerException。
内部异常是:
来自“User_Person”AssociationSet 的关系处于“已删除”状态。给定多重约束,相应的“User_Person_Source”也必须处于“已删除”状态。
这对我来说没有任何意义,因为我没有尝试删除任何内容,而是检查EntityState
两者User
并Person
显示User
处于Added
状态,而Person
处于Unchanged
状态。我已经重写SaveChanges()
以证明:
public override int SaveChanges()
{
var userChanges = ChangeTracker.Entries<User>().Single();
var personChanges = ChangeTracker.Entries<Person>().Single();
if (userChanges.State == EntityState.Deleted)
throw new InvalidOperationException("wtf?");
if (personChanges.State == EntityState.Deleted)
throw new InvalidOperationException("wtf?");
return base.SaveChanges();
}
当这段代码执行时,两者都不会InvalidOperationException
被抛出。再次,userChanges
处于Added
状态,personChanges
处于Unchanged
状态。
我究竟做错了什么?