我的情况是用户可以上传多张照片(一对多)。 用户也可以包含默认照片(一对一)。但是,我实体框架核心2.0 告诉我在使用以下代码时无法识别这种关系:
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; }
}
我如何实现这些多重关系?
EF-Core显示错误:
System.InvalidOperationException:&#39;无法确定导航属性&#39; Photo.Owner&#39;所代表的关系。类型&#39;用户&#39;。手动配置关系,或使用&#39; [NotMapped]&#39;忽略此属性。属性或使用&#39; EntityTypeBuilder.Ignore&#39;在&#39; OnModelCreating&#39;。&#39;
将[InverseProperty("Photos")]
添加到文件模型中的导航属性所有者似乎正在运行。我不确定这是不是正确的方法?
在此图像中File = Photo; Uploader = Owner(与上述型号相当)。
我确认@Ivan在评论中说的是,使用DataAnnotation方法,我在两个方向上获得一对多,而不是一对多和一对一。此图显示了使用InverseProperty
生成的数据库(to实体之间的连接显示了双向一对多关系):
在此图片中File = Photo; Uploader = Owner(与上述型号相当)。
答案 0 :(得分:2)
使用Fluent API建立一对一关系:
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
)关系,必须在两个主键或两个候选键之间建立关系。 (有关详细信息,请查看this blog post。)
EF目前无法通过Annotations设置候选键(也称为唯一键或备用键),因此这是您唯一的选择。在Microsoft Docs上查看EF文档:One to One relationships
更新:早期代码会自动生成UserId
列并正确设置关系。我已将OwnerId
字段添加到Photo
实体,以手动设置关系,如您所愿:
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);
}
}
诀窍在于计算关系(特别是主要结束和从属结束)以及确定哪些需要导航属性。
Inverse属性是必需的,因为EF不知道要映射到Photo.Owner
的属性。这只是在这种情况下使关系明确的一种方式。