EF Core Ссылка на тот же стол, одна коллекция - PullRequest
0 голосов
/ 26 августа 2018

Давайте начнем с результата, который я хотел бы получить.

У меня есть участник, у которого может быть несколько партнеров по танцам.Каждая танцевальная пара связана с курсом.

Итак, модели представлены следующим образом:

Участник:

  • Id
  • ...

Курс:

  • Id
  • ...

MemberPair:

  • Id
  • CourseId
  • 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, и я хотел бы знать, можно ли это сделать проще.

Заранее спасибо.

1 Ответ

0 голосов
/ 26 августа 2018

Ваш комментарий заставил меня искать другие решения.Поэтому, несмотря на тот факт, что вы уже приняли ответ, я хотел изучить некоторые альтернативы.


Проблема с партнером заключается в том, что он относится к члену.С точки зрения member1 member2 является партнером, и наоборот.

Единственный способ реализовать это, более или менее «из коробки», - это добавить избыточные данные.И под этим я подразумеваю добавить данные с обеих точек зрения .

Для этого нам нужно включить Member в MemberPair:

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.

Недостатком является то, что у вас будут избыточные данные, которыми нужно управлять!Но учитывая, что это всего лишь команда из двух человек, я думаю, что это довольно легко реализовать и приемлемое решение.


Альтернативой является расширение объекта Member дополнительным свойством (или методом, если вам нравится).), который генерирует список партнеров.В этом случае вам не нужны ни избыточные данные, ни дополнительная таблица.Но вам нужно будет заполнить обе коллекции 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; }
}

Это позволит использовать более двух партнеров в одной паре, но это то, что вы можете предотвратить спереди.В то время как бэкэнд допускает несколько участников, презентация на фронте по-прежнему состоит из member1 и member2.

Я не тестировал его, но думаю, что вы получите список партнеров:

member.PairMembers
        .Select(p => p.Pair.PairMembers.Where(m => m.MemberId != member.Id))
...