有没有更好的方法来实现这个最终目标,即在同一个表中存储相关多对多实体的易于查询(和包含能力)的横截面?
我开始时没有在连接表中实现TPH,但是这使得在查询中使用一种或另一种类型更具参与性。
// table Related: [Id]
public class Related
{
public Guid Id { get; set; }
public List<RelatedOther> RelatedOthers { get; set; } = new List<RelatedOther>();
public List<RelatedOtherOne> RelatedOtherOnes { get; set; } = new List<RelatedOtherOne>();
public List<RelatedOtherTwo> RelatedOtherTwos { get; set; } = new List<RelatedOtherTwo>();
}
// table RelatedOther: [RelatedId, OtherId, Type]
public abstract class RelatedOther
{
public Guid RelatedId { get; set; }
public Guid OtherId { get; set; }
public Related Related { get; set; }
public Other Other { get; set; }
public abstract RelatedOtherType Type { get; }
}
public class RelatedOtherOne : RelatedOther
{
public override RelatedOtherType Type => RelatedOtherType.One;
// should be unnecessary, 'Other' should be correct type
public OtherOne OtherOne { get; set; }
}
public class RelatedOtherTwo : RelatedOther
{
public override RelatedOtherType Type => RelatedOtherType.Two;
// should be unnecessary, 'Other' should be correct type
public OtherTwo OtherTwo { get; set; }
}
public enum RelatedOtherType : int
{
One = 1,
Two = 2
}
// table Other: [Id, OneProp, TwoProp]
public abstract class Other
{
public Guid Id { get; set; }
public List<RelatedOther> RelatedOthers { get; set; } = new List<RelatedOther>();
}
public class OtherOne : Other
{
public string OneProp { get; set; }
}
public class OtherTwo : Other
{
public string TwoProp { get; set; }
}
TPH已映射like this
M2M在HasKey()
当“相关”实体演变为像“其他”这样的TPH策略时,这变得更加复杂(如果不是不可能的话?)。
答案 0 :(得分:0)
我没有简单的解决方案但是当我偶然发现同样的问题时,我认为我将分享到目前为止我所拥有的一切。
我发现我通常需要将所有或许多类型的关系加载到TPH结构的类中。
所以我使用基多对多类来加载相关对象。因此,这个类不能是抽象的:
public class Event2Location
{
[Required]
public Event Event { get; set; }
public int EventId { get; set; }
[Required]
public Location Location { get; set; }
public int LocationId { get; set; }
public byte EntityType { get; set; }
}
派生类仅添加一些属性以便于访问:
public class Event2Country : Event2Location
{
[NotMapped]
public Country Country
{
get { return base.Location as Country; }
set { base.Location = value; }
}
[NotMapped]
public int CountryId
{
get { return base.LocationId; }
set { base.LocationId = value; }
}
}
在Event
课程中我有:
public virtual ICollection<Event2Location> Event2Locations { get; set; }
[NotMapped]
public virtual ICollection<Event2Country> Event2Countries => Event2Locations?.OfType<Event2Country>().ToList();
// I should probably add some caching here if accessed more often
[NotMapped]
public virtual ICollection<Event2City> Event2Cities => Event2Locations?.OfType<Event2City>().ToList();
所以当我加载连接表时,我可以使用
.Include(e => e.Event2Locations).ThenInclude(j => j.Location)
我可以根据需要使用NotMapped Collections访问特定类型的关系。
我仍然使用派生的Event2 ...类添加新关系。
如您所见,我已将EntityType
列添加到用作TPH鉴别器的多对多类中。如果我不想加载所有这些,我还可以声明要加载哪些类型的关系/实体。
modelBuilder.Entity<Event2Location>()
.HasDiscriminator<byte>("EntityType")
.HasValue<Event2Location>(0)
.HasValue<Event2Country>(1)
这肯定远非完美,但我终于放弃了优化。首先,EFCore必须变得更加成熟。其次,我想看看我是如何实际使用这些结构的。
PS:实际上我的位置TPH结构中有父子关系。在这里,我没有为关系类创建TPH结构(如你所说 - 不可能或至少不合理)。我添加了ParentType和ChildType。因此,我可以确定我实际想要加载哪些关系。然后,我从结果中获取客户端手动需要的类型的相关位置。