EF Core引用同一表,单个集合

时间:2018-08-26 18:06:24

标签: .net-core ef-code-first entity-framework-core

让我们从我想要的结果开始。

我有一个成员,可以有多个舞伴。 每对舞蹈夫妇都必须遵守课程。

所以模型的情况是:

会员:

  • 编号
  • ...

课程:

  • 编号
  • ...

会员对:

  • 编号
  • CourseId
  • Member1Id
  • Member2Id

Entityframework核心为我提供了以下解决方案:

let text = `asdf

asdfsdf
asdf

asdf
23423

dsfddfff`
let matches = text.match(/^[\s\S]+?(\r\n\r\n|\n\n)([\s\S]+)/)
console.log(matches)

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; }
}

我知道理想的解决方案无效。但是,还有另一种更好的解决方案吗? 当我迭代所有成员时,我必须确定是否必须使用MemberPairs1或MemberPairs2,并且我想知道是否可以使此操作更容易。

谢谢。

1 个答案:

答案 0 :(得分:1)

您的评论促使我寻找其他解决方案。因此,尽管您已经接受了答案,但我还是想探索一些替代方法。


合作伙伴的问题是,这是相对于成员而言的。从member1的角度来看,member2是合作伙伴,反之亦然。

或多或少现成的实现此目的的唯一方法是添加冗余数据。我的意思是从两个角度添加数据

为此,我们需要将Member包括在MemberPair中:

<b></b>

假设您有:

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; }
}

〜swap是冗余数据。在这种情况下

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 }

然后您可以查询:

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对象,该属性会生成伙伴列表。在这种情况下,您不需要冗余数据,也不需要其他表。但是您必须填充两个memberPair集合。

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.

原始答案:

问题是您通过将关系保存到一条记录中来破坏该关系。如果您添加一个额外的级别“ Pair”并在其中添加“ PairMembers”,则假设每个课程都有不同的配对,则它看起来像这样:

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:
    Id
    CourseId

PairMember:
    Id
    PairId
    MemberId

这将允许两个以上的伙伴成对出现,但这是您可以避免的。尽管后端允许多个成员,但前端的显示仍然是member1和member2。

我没有测试它,但是我认为这将为您提供合作伙伴列表:

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; }
}