[英]Different behavior across domain objects for same properties in Entity Framework Core 2
I am new to .NET Core and using EF Core 2 我是.NET Core的新手并使用EF Core 2
My domain objects are all derived from a base class with some audit fields on it that get set on SaveChanges
as needed: (Simplified below) 我的域对象都是从基类派生的,基类上有一些审核字段,可以根据需要在SaveChanges
上进行设置:(以下简化)
public abstract class AuditableEntity
{
public DateTime CreatedOn { get; set; }
[ForeignKey("CreatedBy")]
public Guid? CreatedByWebUserId { get; set; }
public WebUser CreatedBy { get; set; }
public DateTime? UpdatedOn { get; set; }
[ForeignKey("UpdatedBy")]
public Guid? UpdatedByWebUserId { get; set; }
public WebUser UpdatedBy { get; set; }
public DateTime? DeletedOn { get; set; }
[ForeignKey("DeletedBy")]
public Guid? DeletedByWebUserId { get; set; }
public WebUser DeletedBy { get; set; }
}
On add-migration, I get the error: 在添加迁移时,出现错误:
Unable to determine the relationship represented by navigation property
'Address.CreatedBy' of type 'WebUser'. Either manually configure the
relationship, or ignore this property using the '[NotMapped]' attribute or by
using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
Address
is one of the classes derived from AuditableEntity
: (Simplified below) Address
是从AuditableEntity
派生的类之一:(以下简化)
public class Address : AuditableEntity
{
public Guid Id { get; set; }
public string Nickname { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string Address3 { get; set; }
public string City { get; set; }
public string StateProvince { get; set; }
public string PostalCode { get; set; }
public string CountryCode { get; set; }
public decimal Latitude { get; set; }
public decimal Longitude { get; set; }
}
However, I have several objects that use the same "agent and timestamp" pair pattern similar to the above that work just fine such as: 但是,我有几个对象使用与上面类似的相同“代理程序和时间戳”对模式,它们工作得很好,例如:
public DateTime? VerifiedOn { get; set; }
[ForeignKey("VerifiedBy")]
public Guid? VerifiedByWebUserId { get; set; }
public WebUser VerifiedBy { get; set; }
The error always comes from Address
, and if I remove the base class from Address everything works fine (meaning, these fields get successfully applied to my 15+ other domain objects). 该错误始终来自Address
,如果我从Address
删除基类,一切正常(这意味着这些字段已成功应用于我的15个以上其他域对象)。
The issue seemingly stems from WebUser
having a reference to Address
: (Simplified below) 该问题似乎是由于WebUser
引用了Address
:(以下简化)
public class WebUser : AuditableEntity
{
public Guid Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
public string Phone1 { get; set; }
public string Phone1Type { get; set; }
public string Phone2 { get; set; }
public string Phone2Type { get; set; }
[ForeignKey("AddressId")]
public Address Address { get; set; }
public Guid? AddressId { get; set; }
}
What is the correct way of creating these references prioritizing keeping the FK constraints (over keeping the ability to navigate)? 创建这些引用的优先顺序是保持FK约束优先(而不是保持导航能力)的正确方法是什么?
The problem is unrelated to the usage of a base class (the same will happen if you remove the base class, but copy its properties to Address
class), but the multiple cross references between the two classes. 该问题与基类的使用无关(如果删除基类, 但是将其属性复制到Address
类,也会发生相同的情况),但是两个类之间存在多个交叉引用。
By convention EF Core tries to automatically "pair" navigation properties of the two entities in order to form a single relationship, which succeeds in most of the cases. 按照约定,EF Core会尝试自动“配对”两个实体的导航属性以形成单个关系,这种关系在大多数情况下都是成功的。 However in this case the WebUser
has Address
type navigation property and Address
class has WebUser
type navigation property (actually 3). 但是,在这种情况下, WebUser
具有“ Address
类型导航属性,而“ Address
类具有“ WebUser
类型导航属性(实际上为3)。
Since all they have associated FK property via ForeignKey
data annotation, EF Core should be able to correctly identify them as different one-to-many relationships, but it doesn't. 由于它们都具有通过ForeignKey
数据注释关联的FK属性,因此EF Core应该能够正确地将它们标识为不同的一对多关系,但事实并非如此。 Not only it fails with the exception in question, but also doesn't create FK relationships for the WebUser
. 它不仅会因所讨论的异常而失败,而且不会为WebUser
创建FK关系。
Everything works correctly if the base class contains only 1 WebUser
type of navigation property, so I'm assuming thet unfortunately you are hitting some current EF Core bug. 如果基类仅包含1种WebUser
类型的导航属性,则一切正常,因此,我很不幸地假设您遇到了一些当前的EF Core错误。
As a workaround until they fixed it, I would suggest explicitly configuring the problematic relationships using fluent API, by overriding the OnModelCreating
and adding the following code: 作为一种解决方法,直到他们修复它,我建议通过重写OnModelCreating
并添加以下代码,使用流畅的API显式配置有问题的关系:
var auditableEntityTypes = modelBuilder.Model.GetEntityTypes().Where(t => t.ClrType.IsSubclassOf(typeof(AuditableEntity)));
var webUserNavigations = new[] { nameof(AuditableEntity.CreatedBy), nameof(AuditableEntity.DeletedBy), nameof(AuditableEntity.UpdatedBy) };
foreach (var entityType in auditableEntityTypes)
{
modelBuilder.Entity(entityType.ClrType, builder =>
{
foreach (var webUserNavigation in webUserNavigations)
builder.HasOne(typeof(WebUser), webUserNavigation).WithMany();
});
}
ie for each entity class that derives from AuditableEntity
we explicitly configure the 3 WebUser
reference navigation properties to be mapped to 3 separate one-to-many relationships with no inverse collection navigation properties. 例如,对于从AuditableEntity
派生的每个实体类,我们显式配置3个WebUser
参考导航属性以映射到3个独立的一对多关系,而没有逆集合导航属性。 Once we do that, EF Core has no problem to correctly map the WebUser.Address
FK association. 一旦完成此操作,EF Core就可以正确映射WebUser.Address
FK关联。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.