简体   繁体   English

实体框架Core 2中相同属性的跨域对象的行为不同

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM