考虑以下类:
public class Kid
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Date Time BirthDate { get; set; }
public ProfilePhoto CurrentProfilePhoto { get; set; }
public virtual ICollection<ProfilePhoto> ProfilePhotos { get; set; }
}
public class ProfilePhoto
{
public int Id { get; set; }
public byte[] PhotoData { get; set; }
public DateTime DateTaken { get; set; }
public DateTime DateUploaded { get; set; }
public int KidID { get; set; }
public Kid Kid { get; set; }
}
每个孩子实体都有多个个人资料照片,但它可能有或没有一个当前的个人资料照片。另一方面,每个ProfilePhoto都与一个孩子相关,并且该孩子的一个ProfilePhoto只能是当前的个人资料照片。如何在EntityFramework 6.4中使用DataAnnotations或FluentAPI(如果可能的话,我更喜欢使用DataAnnotations)来表示这些关系。
您可以使用以下三种方法:
选项1:将CurrentProfilePhotoId属性添加到Kid中,作为CurrentProfilePhoto导航属性的FK。
[ForeignKey("CurrentProfilePhoto")]
public int? CurrentProfilePhotoId { get; set; }
public virtual ProphilePhoto CurrentProfilePhoto { get; set; }
选项2:将CurrentProfilePhoto标记为[NotMapped]
,并从ProfilePhotos集合中计算客户端:
[NotMapped]
public ProphilePhoto CurrentProfilePhoto
{
get { return ProfilePhotos.OrderByDescending(x => x.DateTaken).FirstOrDefault(); }
}
选项3:从实体中删除CurrentProfilePhoto,并在需要当前照片时依赖于对ViewModel的投影。例如
var kid = context.Kids
.Where(x => x.Id == kidId)
.Select(x => new KidDetailViewModel
{
Id = x.Id,
Name = x.LastName + ", " + x.FirstName,
BirthDate = x.BirthDate,
CurrentProfilePhoto = x.ProfilePhotos
.OrderByDescending(p => p.DateTaken)
.FirstOrDefault()
}).Single();
选项1是相当简单的,然而没有办法显式强制任何照片被CurrentProfilePhotoId引用是那个孩子的照片。它可能会意外地关联到与该Kid ID无关的任何其他记录的照片。当使用这样的引用时,建议您在数据库中设置数据完整性检查作业,以便在CurrentPhotoId引用的照片具有不同的Kid ID时提醒您。
选项2确保当前照片总是与那个孩子相关联,但是你要么需要记住在加载一个孩子时总是渴望加载整个ProfilePhotos集合,否则它会触发该集合的惰性加载以获得当前照片。
选项3是我推荐的习惯投影的方法。这样可以确保只引用那个孩子的照片,并生成一个查询,该查询只提取足够的数据来填充您在特定时间需要的数据。在这个例子中,只有一张照片和必要的细节会从Kid记录中被拉回来。