C# EF7实施TPH和x2B;M2M
有没有更好的方法来实现这个最终目标,即在同一个表中存储相关的多对多实体的可轻松查询(并包含)的横截面 我一开始没有在联接表中实现TPH,但这使得在查询中使用一种或另一种类型更加复杂,afaictC# EF7实施TPH和x2B;M2M,c#,entity-framework,entity-framework-core,C#,Entity Framework,Entity Framework Core,有没有更好的方法来实现这个最终目标,即在同一个表中存储相关的多对多实体的可轻松查询(并包含)的横截面 我一开始没有在联接表中实现TPH,但这使得在查询中使用一种或另一种类型更加复杂,afaict // table Related: [Id] public class Related { public Guid Id { get; set; } public List<RelatedOther> RelatedOthers { get; set; } = new Lis
// 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; }
}
//表相关:[Id]
公共类相关
{
公共Guid Id{get;set;}
public List RelatedOthers{get;set;}=new List();
public List relatedOtherOne{get;set;}=new List();
public List RelatedOtherTwos{get;set;}=new List();
}
//表RelatedOther:[RelatedId,OtherId,Type]
公共抽象类RelatedOther
{
公共Guid RelatedId{get;set;}
公共Guid OtherId{get;set;}
公共相关的{get;set;}
公共其他{get;set;}
公共抽象RelatedOtherType{get;}
}
公共类RelatedOtherOne:RelatedOther
{
公共覆盖RelatedOtherType=>RelatedOtherType.One;
//应为不必要,“其他”应为正确类型
公共OtherOne OtherOne{get;set;}
}
公共类RelatedOther二:RelatedOther
{
公共覆盖RelatedOtherType=>RelatedOtherType.Two;
//应为不必要,“其他”应为正确类型
public OtherTwo OtherTwo{get;set;}
}
公共枚举RelatedOtherType:int
{
1=1,
二=2
}
//表其他:[Id,OneProp,TwoProp]
公共抽象类其他
{
公共Guid Id{get;set;}
public List RelatedOthers{get;set;}=new List();
}
公共类其他一个:其他
{
公共字符串OneProp{get;set;}
}
公共类其他二:其他
{
公共字符串TwoProp{get;set;}
}
TPH已映射M2M在HasKey()中映射+鉴别器
当“相关”实体演变为类似于“其他”的TPH战略时,这变得更加复杂(如果不是不可能?) 我没有简单的解决办法,但当我偶然发现同样的问题时,我想我将分享我迄今为止的成果 我发现我通常需要将所有或多种类型的关系加载到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; }
}
}
在事件中
类别I有:
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();
我可以根据需要使用NotMapped集合访问特定类型的关系
我仍然使用派生的Event2。。。类以添加新关系
如您所见,我已将一列EntityType
添加到我用作TPH鉴别器的多对多类中。通过此列,我还可以声明如果我不想加载所有类型的关系/实体,我希望加载哪些类型的关系/实体
modelBuilder.Entity<Event2Location>()
.HasDiscriminator<byte>("EntityType")
.HasValue<Event2Location>(0)
.HasValue<Event2Country>(1)
modelBuilder.Entity()
.HasDiscriminator(“EntityType”)
.HasValue(0)
.HasValue(1)
这肯定远远不够完美,但我最终放弃了优化它。首先,EFCore必须变得更加成熟。其次,我想看看我是如何实际使用这些结构的
PS:实际上我的位置TPH结构中有父子关系。在这里,我没有为Relationship类创建TPH结构(正如您所说的——不可能或至少不合理)。我添加了ParentType和ChildType。因此,我可以确定实际要加载哪些关系。然后,从结果中手动获取客户端所需类型的相关位置 我没有简单的解决办法,但当我偶然发现同样的问题时,我想我将分享我迄今为止的成果 我发现我通常需要将所有或多种类型的关系加载到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; }
}
}
在事件中
类别I有:
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();
我可以根据需要使用NotMapped集合访问特定类型的关系
我仍然使用派生的Event2。。。类以添加新关系
如您所见,我已将一列EntityType
添加到我用作TPH鉴别器的多对多类中。通过此列,我还可以声明如果我不想加载所有类型的关系/实体,我希望加载哪些类型的关系/实体
modelBuilder.Entity<Event2Location>()
.HasDiscriminator<byte>("EntityType")
.HasValue<Event2Location>(0)
.HasValue<Event2Country>(1)
modelBuilder.Entity()
.HasDiscriminator(“EntityType”)
.HasValue(0)
.HasValue(1)
这肯定远远不够完美,但我最终放弃了优化它。首先,EFCore必须变得更加成熟。其次,我想看看我是如何实际使用这些结构的
PS:实际上我的位置TPH结构中有父子关系。在这里,我没有为Relationship类创建TPH结构(正如您所说的——不可能或至少不合理)。我添加了ParentType和ChildType。因此,我可以确定实际要加载哪些关系。然后,从结果中手动获取客户端所需类型的相关位置 我决定,如果m2m关联的末端是TPH,那么联接表本身也应该反映该TPH,不管我是否为所有这些TPH类型在任何一端公开导航属性。在我看来,这只是一个更简洁的设计。这将允许框架处理您作为
[notmap]进行的导航属性转换
使用cast。当我在基类上使用abstract
时,它不会阻止我仅对该基类进行查询-如果查询的结果集为多个派生类型,EF将实例化正确的派生类型,相应派生类型中的实例将自动填充该实例。如果您的模型有2个(并且只有2个)派生类型,那么基类应该是抽象的。没有EventType鉴别器值的Event2Location实例实际上没有意义,对吗?所以你永远都不应该相信