如何定义两个实体之间的多个关系? [英] How to define multiple relationships between two entities?
问题描述
我有一种情况,用户可以上传多张照片(一对多)。 用户也可以具有默认照片(一对一)。但是,我实体框架核心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屋!