如何定义两个实体之间的多个关系? [英] How to define multiple relationships between two entities?

查看:755
本文介绍了如何定义两个实体之间的多个关系?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一种情况,用户可以上传多张照片(一对多)。 用户也可以具有默认照片(一对一)。但是,我实体框架核心2.0 告诉我,当我使用以下代码时,他无法识别这种关系:

I have the scenario where a user can upload multiple photos (One-to-Many). The user also can have a default photo (One-to-One). However, I entity framework core 2.0 tells that he cannot recognize the relationship when I use the following code:

public class User
{
    public Guid Id { get; set; }

    public ICollection<Photo> Photos{ get; set; }

    public Photo DefaultPhoto { get; set; }
    [ForeignKey("DefaultPhoto")]
    public Guid DefaultPhotoId { get; set; }
}

public class Photo
{
    public Guid Id { get; set; }

    public User Owner { get; set; }
}

我如何实现这些多重关系?

How may I achieve these multiple relationships?

EF-Core显示错误:

There error shown by EF-Core:


System.InvalidOperationException:'无法确定类型为'User'的导航属性'Photo.Owner'表示的关系。要么手动配置关系,要么使用'[NotMapped]'属性或通过'OnModelCreating'中的'EntityTypeBuilder.Ignore'忽略此属性。'

System.InvalidOperationException: 'Unable to determine the relationship represented by navigation property 'Photo.Owner' of type 'User'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.'


更新:


[InverseProperty(照片))添加到导航属性所有者中文件模型似乎正在运行。我不确定这是否正确吗?

UPDATE:

Adding [InverseProperty("Photos")] to the navigation property Owner in File Model seems to be working. I am not sure if that is the correct way?


在此图片中File = Photo; Uploader = Owner(与上述模型相当)。

我确认@Ivan在注释,使用DataAnnotation方法,我在两个方向上获得了一对多,而不是一对多和一对一。此图显示了使用 InverseProperty 生成的数据库(to实体之间的连接显示了双向的一对多关系):

I confirm what @Ivan said in the comments, with DataAnnotation approach, I get One-to-Many in two directions instead of One-to-Many and One-to-One. This figure shows the generated database by using InverseProperty (the connection between the to entities show the bi-directional One-to-Many relationship):

在此图片中File = Photo; Uploader = Owner(与上述模型相当)。

推荐答案

使用Fluent API建立一个一对一关系:

Use the Fluent API to establish the one-to-one relationship:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // Establish a one to one relationship with the
    // User as the dependent End
    modelBuilder.Entity<User>()
        .HasOne(u => u.DefaultPhoto)
        .WithOne(p => p.Owner)
        .HasForeignKey<User>(u => u.DefaultPhotoId);
}

对于一对一关系( 1:0..1 )关系,则必须在两个主键或两个候选键之间建立关系。 (请查看此博客文章以获得更多信息。)

For a relationship to be a one-to-one (1:0..1) relationship, the relationship must be established between two primary keys or two candidate keys. (Check this blog post for more info on this.)

EF目前无法通过注释设置候选键(也称为唯一键或备用键),因此这是您唯一的选择。在Microsoft文档中查看EF文档:一个一对一关系

EF has no way of setting a candidate key (also called unique or alternate key) via Annotations right now, so this is your only option. Check the EF docs here at Microsoft Docs: One to One relationships

更新:较早的代码会自动生成 UserId 列并正确设置关系。我已将 OwnerId 字段添加到 Photo 实体以手动设置关系,如您所愿:

Update: The earlier code would automatically generate a UserId column and sets up relationships correctly. I've added the OwnerId field to the Photo entity to manually set the relationship, like you wanted:

public class User
{
    public Guid Id { get; set; }

    [InverseProperty("Owner")]
    public ICollection<Photo> Photos{ get; set; }

    public Photo DefaultPhoto { get; set; }
    public Guid DefaultPhotoId { get; set; }
}

public class Photo
{
    public Guid Id { get; set; }

    public Guid OwnerId { get; set; }
    public User Owner { get; set; }
}

public class MyDbContext : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<Photo> Photos { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // You may use this instead of the inverse property
        // // The One to Many relationship between
        // // User.Id (Principal End) and Photo.OwnerId
        // modelBuilder.Entity<Photo>()
        //     .HasOne(p => p.Owner)
        //     .WithMany(u => u.Photos)
        //     .HasForeignKey(p => p.OwnerId);

        // Establishes 1:0..1 relationship between
        // Photo.Id (Principal End) and User.DefaultPhoto (Dependent end)
        modelBuilder.Entity<User>()
            .HasOne(u => u.DefaultPhoto)
            .WithOne() // we leave this empty because it doesn't correspond to a navigation property in the Photos table
            .HasForeignKey<User>(u => u.DefaultPhotoId);
    }
}

诀窍在于弄清关系(尤其是本金

The trick is in figuring the relationships (especially the principal end and the dependent ends) and in figuring which ones require navigation properties.

需要反向属性,因为EF不知道要映射到<$ c $的哪个属性c> Photo.Owner 。在这种情况下,这只是使关系明确的一种方法。

The Inverse property is required because EF doesn't know which property to map to Photo.Owner. It's just a way of making a relationship explicit in cases like these.

这篇关于如何定义两个实体之间的多个关系?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆