EF Core 引用相同 table,单个集合
EF Core Referencing same table, single collection
让我们从我想要的结果开始。
我有一个成员可以有多个舞伴。
每对舞伴都绑定一个课程。
所以模特的情况是:
成员:
- 编号
- ...
课程:
- 编号
- ...
成员对:
- 编号
- 课程编号
- Member1Id
- Member2Id
Entityframework 核心给了我以下解决方案:
public class MemberPair : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public Guid Member1Id { get; set; }
[Required]
public Guid Member2Id { get; set; }
[Required]
public Guid CourseId { get; set; }
public virtual Member Member1 { get; set; }
public virtual Member Member2 { get; set; }
public virtual Course Course { get; set; }
}
和
public class Member : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
...
public virtual List<MemberPair> MemberPairs1 { get; set; }
public virtual List<MemberPair> MemberPairs2 { get; set; }
}
但我理想的解决方案是:
public class MemberPair : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public Guid PartnerId { get; set; }
[Required]
public Guid CourseId { get; set; }
public virtual Member Partner{ get; set; }
public virtual Course Course { get; set; }
}
和
public class Member : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
...
public virtual List<MemberPair> Partners { get; set; }
}
我知道理想的解决方案是无效的。但是还有其他更好的解决方案吗?
当我迭代所有成员时,我必须确定我是否必须使用 MemberPairs1 或 MemberPairs2 ,我想知道这是否可以变得更容易。
提前致谢。
您的评论促使我搜索其他解决方案。因此,尽管您已经接受了答案,但我还是想探索一些替代方案。
合作伙伴的问题在于这是相对于成员而言的。从member1的角度来看,member2是合作伙伴,反之亦然。
实现这一点的唯一方法,或多或少是开箱即用的,是添加冗余数据。我的意思是 从两个角度添加数据。
为此,我们需要在 MemberPair 中包含 Member:
public class MemberPair : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public Guid MemberId { get; set; }
[Required]
public Guid PartnerId { get; set; }
[Required]
public Guid CourseId { get; set; }
public Member Member { get; set; }
public Member Partner { get; set; }
public Course Course { get; set; }
}
假设你有:
Pair1 = { Id = 1, MemberId = 1, PartnerId = 2, CourseId = 1 }
Pair1Swap = { Id = 2, MemberId = 2, PartnerId = 1, CourseId = 1 }
Pair2 = { Id = 3, MemberId = 1, PartnerId = 3, CourseId = 2 }
Pair2Swap = { Id = 4, MemberId = 3, PartnerId = 1, CourseId = 2 }
其中~swap为冗余数据。在那种情况下
public class Member : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
// As the data is redundant only look at memberId. Check the fluent code.
// MemberPairs should contain a list of pairs where 'this' is a member.
// When (Member)Id == 1 then Pair1 + Pair2
// When (Member)Id == 2 then Pair1Swap
public ICollection<MemberPair> MemberPairs { get; set; }
}
之后可以查询:
member.MemberPairs.Select(p => p.Partner);
// result for Id==1: Partner with Id 2 and Partner with Id 3.
// result for Id==2: Partner with Id 1.
缺点是会有冗余数据,需要管理!但考虑到这只是一个两人团队,我认为这很容易实现并且是一个可以接受table的解决方案。
另一种方法是使用额外的 属性(或方法,如果您愿意)扩展 Member 对象,从而生成合作伙伴列表。在那种情况下,您不需要冗余数据,也不需要额外的 table。但是您必须填充两个 memberPair 集合。
public class Member : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public List<MemberPair> MemberPairs1 { get; set; }
public List<MemberPair> MemberPairs2 { get; set; }
public ICollection<Member> Partners
{
get
{
// Get all pairs where 'this' is a member.
var pairs = MemberPairs1.Union(MemberPairs2);
// Get all partners by filtering by Id.
return pairs.Select(p => p.MemberId1 == Id ? p.MemberId2 : p.MemberId1);
}
}
}
原回答:
问题是您通过将关系保存到一条记录中来破坏关系。如果你添加一个额外的级别 'Pair' 并向其添加 'PairMembers',那么它看起来像这样,假设每门课程都有不同的对:
Pair:
Id
CourseId
PairMember:
Id
PairId
MemberId
会变成这样:
public class Pair : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public Guid CourseId { get; set; }
public Course Course { get; set; }
public ICollection<PairMember> PairMembers { get; set; }
}
public class PairMember : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public Guid PairId { get; set; }
[Required]
public Guid MemberId { get; set; }
public Pair Pair { get; set; }
public Member MemberId { get; set; }
}
public class Member : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public ICollection<PairMember> PairMembers { get; set; }
}
这将允许两个以上的伙伴组成一对,但这是你可以在前面防止的事情。虽然后台允许多个member,但是前台的呈现还是member1和member2。
我没有测试过,但我想这会为您提供合作伙伴列表:
member.PairMembers
.Select(p => p.Pair.PairMembers.Where(m => m.MemberId != member.Id))
让我们从我想要的结果开始。
我有一个成员可以有多个舞伴。 每对舞伴都绑定一个课程。
所以模特的情况是:
成员:
- 编号
- ...
课程:
- 编号
- ...
成员对:
- 编号
- 课程编号
- Member1Id
- Member2Id
Entityframework 核心给了我以下解决方案:
public class MemberPair : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public Guid Member1Id { get; set; }
[Required]
public Guid Member2Id { get; set; }
[Required]
public Guid CourseId { get; set; }
public virtual Member Member1 { get; set; }
public virtual Member Member2 { get; set; }
public virtual Course Course { get; set; }
}
和
public class Member : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
...
public virtual List<MemberPair> MemberPairs1 { get; set; }
public virtual List<MemberPair> MemberPairs2 { get; set; }
}
但我理想的解决方案是:
public class MemberPair : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public Guid PartnerId { get; set; }
[Required]
public Guid CourseId { get; set; }
public virtual Member Partner{ get; set; }
public virtual Course Course { get; set; }
}
和
public class Member : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
...
public virtual List<MemberPair> Partners { get; set; }
}
我知道理想的解决方案是无效的。但是还有其他更好的解决方案吗? 当我迭代所有成员时,我必须确定我是否必须使用 MemberPairs1 或 MemberPairs2 ,我想知道这是否可以变得更容易。
提前致谢。
您的评论促使我搜索其他解决方案。因此,尽管您已经接受了答案,但我还是想探索一些替代方案。
合作伙伴的问题在于这是相对于成员而言的。从member1的角度来看,member2是合作伙伴,反之亦然。
实现这一点的唯一方法,或多或少是开箱即用的,是添加冗余数据。我的意思是 从两个角度添加数据。
为此,我们需要在 MemberPair 中包含 Member:
public class MemberPair : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public Guid MemberId { get; set; }
[Required]
public Guid PartnerId { get; set; }
[Required]
public Guid CourseId { get; set; }
public Member Member { get; set; }
public Member Partner { get; set; }
public Course Course { get; set; }
}
假设你有:
Pair1 = { Id = 1, MemberId = 1, PartnerId = 2, CourseId = 1 }
Pair1Swap = { Id = 2, MemberId = 2, PartnerId = 1, CourseId = 1 }
Pair2 = { Id = 3, MemberId = 1, PartnerId = 3, CourseId = 2 }
Pair2Swap = { Id = 4, MemberId = 3, PartnerId = 1, CourseId = 2 }
其中~swap为冗余数据。在那种情况下
public class Member : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
// As the data is redundant only look at memberId. Check the fluent code.
// MemberPairs should contain a list of pairs where 'this' is a member.
// When (Member)Id == 1 then Pair1 + Pair2
// When (Member)Id == 2 then Pair1Swap
public ICollection<MemberPair> MemberPairs { get; set; }
}
之后可以查询:
member.MemberPairs.Select(p => p.Partner);
// result for Id==1: Partner with Id 2 and Partner with Id 3.
// result for Id==2: Partner with Id 1.
缺点是会有冗余数据,需要管理!但考虑到这只是一个两人团队,我认为这很容易实现并且是一个可以接受table的解决方案。
另一种方法是使用额外的 属性(或方法,如果您愿意)扩展 Member 对象,从而生成合作伙伴列表。在那种情况下,您不需要冗余数据,也不需要额外的 table。但是您必须填充两个 memberPair 集合。
public class Member : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public List<MemberPair> MemberPairs1 { get; set; }
public List<MemberPair> MemberPairs2 { get; set; }
public ICollection<Member> Partners
{
get
{
// Get all pairs where 'this' is a member.
var pairs = MemberPairs1.Union(MemberPairs2);
// Get all partners by filtering by Id.
return pairs.Select(p => p.MemberId1 == Id ? p.MemberId2 : p.MemberId1);
}
}
}
原回答:
问题是您通过将关系保存到一条记录中来破坏关系。如果你添加一个额外的级别 'Pair' 并向其添加 'PairMembers',那么它看起来像这样,假设每门课程都有不同的对:
Pair:
Id
CourseId
PairMember:
Id
PairId
MemberId
会变成这样:
public class Pair : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public Guid CourseId { get; set; }
public Course Course { get; set; }
public ICollection<PairMember> PairMembers { get; set; }
}
public class PairMember : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public Guid PairId { get; set; }
[Required]
public Guid MemberId { get; set; }
public Pair Pair { get; set; }
public Member MemberId { get; set; }
}
public class Member : AuditableEntity, IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public ICollection<PairMember> PairMembers { get; set; }
}
这将允许两个以上的伙伴组成一对,但这是你可以在前面防止的事情。虽然后台允许多个member,但是前台的呈现还是member1和member2。
我没有测试过,但我想这会为您提供合作伙伴列表:
member.PairMembers
.Select(p => p.Pair.PairMembers.Where(m => m.MemberId != member.Id))