EF6 插入复合键记录错误
EF6 Inserting Composite key record errors
我遇到了一个有趣的难题,我希望其他人能够帮助阐明一些问题。
当使用 EF6 向 table 插入一个新条目时,该 table 具有由两个 Guid 组成的复合键,其中一个成员将从 DB 分配,而另一个成员的值由应用程序 i 提供我得到的反应不一。
对于一个 table 插入没有任何问题,而对于另一个具有完全相同的键和标识列设置的插入失败并显示消息'InvalidOperationException:ReferentialConstraint 中的依赖 属性 是映射到存储生成的列。列:'ID'。'以下是(简化的)classes 及其配置设置
插入失败的Class:
public class User
{
public Guid ID { get; set; }
public Guid CompanyId { get; set; }
public Guid OrganisationId { get; set; }
public String PasswordHash { get; set; }
public String Salt { get; set; }
public String UserName { get; set; }
public virtual Company Company { get; set; }
public virtual Organisation Organisation { get; set; }
// <inconsequential members omitted>
}
public class UserConfiguration : EntityTypeConfiguration<User>
{
public UserConfiguration()
{
HasKey(u => new { u.CompanyId, u.ID });
Property(u => u.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(u => u.UserName).IsRequired().HasMaxLength(256);
Property(u => u.PasswordHash).IsRequired().HasMaxLength(256);
Property(u => u.Salt).IsRequired().HasMaxLength(256);
HasRequired(c => c.Company).WithMany(c => c.Users).HasForeignKey(c => c.CompanyId).WillCascadeOnDelete(false);
HasRequired(c => c.Organization).WithMany(c => c.Users).HasForeignKey(p => p.OrganizationID).WillCascadeOnDelete(false);
// < inconsequential members omitted>
}
}
插入没有问题的Class:
public class AdditionalInformation
{
public Guid ID { get; set; }
public Guid CompanyId { get; set; }
public Guid CustomFieldId { get; set; }
public Guid UserId{ get; set; }
public virtual Company Company { get; set; }
public virtual User User { get; set; }
// <inconsequential members omitted>
}
public class AdditionalInformationConfiguration : EntityTypeConfiguration<AdditionalInformation>
{
public AdditionalInformationConfiguration()
{
HasKey(ai => new { ai.CompanyId, ai.ID });
Property(u => u.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
HasOptional(ai => ai.User).WithMany(u => u.UserAdditionalInformations).HasForeignKey(ai => new { ai.CompanyId, ai.UserID });
// <inconsequential members omitted>
}
}
我一直在使用的简单测试:
using (var context = new DataContext())
{
var user = context.Users.First(f => f.Company.Subdomain.StartsWith("demo"));
var customField = context.CustomFields.First(f => f.CompanyId == user.CompanyId);
context.Users.Add(new User() { CompanyId = user.CompanyId, PasswordHash = "hash", Salt = "salt", UserName = "anew@entry.com" });
context.AdditionalInformations.Add(new UserAdditionalInformation() { CustomFieldID = customField.ID, CompanyId = user.CompanyId, UserID = user.ID });
context.SaveChanges();
}
如您所见,两个 classes 都有一个 ID 成员和一个 CompanyId 成员。他们都将密钥定义为 { CompanyId, Id } 和 ID 成员上的 DatabaseGeneratedOption.Identity。
我很困惑为什么当 AdditionalInformation
class 的实例通过 DbContext 持久保存到数据库时,记录创建时没有问题,而 User
class 抛出 'InvalidOperationException:ReferentialConstraint 中的相关 属性 映射到存储生成的列。列:'ID'。'错误。
我已经设法解决了我自己的问题,但无法解释该修复是如何产生效果的。
用户对象有一个导航 属性 到另一个 table,它没有公开用户对象上的 FK 列。一旦推断列暴露,插入问题就消失了。
我偶然发现了这个,因为在试图理解问题时我注意到这个 FK 没有明确暴露,所以这样做了,然后发现我的单元测试在更改后开始工作。
我遇到了一个有趣的难题,我希望其他人能够帮助阐明一些问题。
当使用 EF6 向 table 插入一个新条目时,该 table 具有由两个 Guid 组成的复合键,其中一个成员将从 DB 分配,而另一个成员的值由应用程序 i 提供我得到的反应不一。
对于一个 table 插入没有任何问题,而对于另一个具有完全相同的键和标识列设置的插入失败并显示消息'InvalidOperationException:ReferentialConstraint 中的依赖 属性 是映射到存储生成的列。列:'ID'。'以下是(简化的)classes 及其配置设置
插入失败的Class:
public class User
{
public Guid ID { get; set; }
public Guid CompanyId { get; set; }
public Guid OrganisationId { get; set; }
public String PasswordHash { get; set; }
public String Salt { get; set; }
public String UserName { get; set; }
public virtual Company Company { get; set; }
public virtual Organisation Organisation { get; set; }
// <inconsequential members omitted>
}
public class UserConfiguration : EntityTypeConfiguration<User>
{
public UserConfiguration()
{
HasKey(u => new { u.CompanyId, u.ID });
Property(u => u.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(u => u.UserName).IsRequired().HasMaxLength(256);
Property(u => u.PasswordHash).IsRequired().HasMaxLength(256);
Property(u => u.Salt).IsRequired().HasMaxLength(256);
HasRequired(c => c.Company).WithMany(c => c.Users).HasForeignKey(c => c.CompanyId).WillCascadeOnDelete(false);
HasRequired(c => c.Organization).WithMany(c => c.Users).HasForeignKey(p => p.OrganizationID).WillCascadeOnDelete(false);
// < inconsequential members omitted>
}
}
插入没有问题的Class:
public class AdditionalInformation
{
public Guid ID { get; set; }
public Guid CompanyId { get; set; }
public Guid CustomFieldId { get; set; }
public Guid UserId{ get; set; }
public virtual Company Company { get; set; }
public virtual User User { get; set; }
// <inconsequential members omitted>
}
public class AdditionalInformationConfiguration : EntityTypeConfiguration<AdditionalInformation>
{
public AdditionalInformationConfiguration()
{
HasKey(ai => new { ai.CompanyId, ai.ID });
Property(u => u.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
HasOptional(ai => ai.User).WithMany(u => u.UserAdditionalInformations).HasForeignKey(ai => new { ai.CompanyId, ai.UserID });
// <inconsequential members omitted>
}
}
我一直在使用的简单测试:
using (var context = new DataContext())
{
var user = context.Users.First(f => f.Company.Subdomain.StartsWith("demo"));
var customField = context.CustomFields.First(f => f.CompanyId == user.CompanyId);
context.Users.Add(new User() { CompanyId = user.CompanyId, PasswordHash = "hash", Salt = "salt", UserName = "anew@entry.com" });
context.AdditionalInformations.Add(new UserAdditionalInformation() { CustomFieldID = customField.ID, CompanyId = user.CompanyId, UserID = user.ID });
context.SaveChanges();
}
如您所见,两个 classes 都有一个 ID 成员和一个 CompanyId 成员。他们都将密钥定义为 { CompanyId, Id } 和 ID 成员上的 DatabaseGeneratedOption.Identity。
我很困惑为什么当 AdditionalInformation
class 的实例通过 DbContext 持久保存到数据库时,记录创建时没有问题,而 User
class 抛出 'InvalidOperationException:ReferentialConstraint 中的相关 属性 映射到存储生成的列。列:'ID'。'错误。
我已经设法解决了我自己的问题,但无法解释该修复是如何产生效果的。
用户对象有一个导航 属性 到另一个 table,它没有公开用户对象上的 FK 列。一旦推断列暴露,插入问题就消失了。
我偶然发现了这个,因为在试图理解问题时我注意到这个 FK 没有明确暴露,所以这样做了,然后发现我的单元测试在更改后开始工作。