How to define multiple relationships between two entities?

做~自己de王妃 提交于 2019-12-10 17:17:40

问题


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?

There error shown by EF-Core:

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'.'

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?

In this image File=Photo; Uploader=Owner (to be comparable with the above model).

UPDATE 2:

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):

In this image File=Photo; Uploader=Owner (to be comparable with the above model).


回答1:


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);
}

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 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


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.

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.



来源:https://stackoverflow.com/questions/47728331/how-to-define-multiple-relationships-between-two-entities

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!