EF Code First: многие ко многим и один ко многим - PullRequest
6 голосов
/ 03 июня 2011

Это, вероятно, только потому, что мне не хватает моих знаний по беглому API EF Code First, но я в замешательстве.

Я хочу смоделировать следующее:

  • A Группы коллекция с Id и именем
  • A Пользователи коллекция с Id и именем
  • Каждому пользователю назначается ровно одна первичная группа
  • У каждого пользователя может быть ноль или много вторичных групп.

Структура таблицы, для которой я собираюсь выглядеть, будет выглядеть следующим образом:

Группы

  • Id
  • Имя

Пользователи

  • Id
  • Имя
  • PrimaryGroupId

SecondaryGroupAssignments

  • UserId
  • GroupId

Я бьюсь головойпротив стены, пытающейся смоделировать это с помощью EF Code First, но я не могу заставить ее принять обе отношения между пользователем и группой.Извините за то, что не выложил никакого кода .NET (я рад), но, вероятно, все равно все не так.

Есть ли способ сделать модель EF такой?Я предполагаю, что мне нужно сделать какую-то настройку с Fluent API.Может быть, лучше спросить: есть ли хорошая, точная ссылка на Fluent API?

Спасибо!

Ответы [ 2 ]

16 голосов
/ 03 июня 2011

Попробуйте это (не проверено):

public class Group 
{
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<User> PrimaryUsers { get; set; }
    public virtual ICollection<User> SecondaryUsers { get; set; } 
}

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int PrimaryGroupId { get; set; }

    public virtual Group PrimaryGroup { get; set; }
    public virtual ICollection<Group> SecondaryGroups { get; set; }
}

public class Context : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<Group> Groups { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<User>()
                    .HasRequired(u => u.PrimaryGroup)
                    .WithMany(g => g.PrimaryUsers)
                    .HasForeignKey(u => u.PrimaryGroupId)
                    .WillCascadeOnDelete(false);

        modelBuilder.Entity<User>()
                    .HasMany(u => u.SecondaryGroups)
                    .WithMany(g => g.SecondaryUsers)
                    .Map(m => m.MapLeftKey("UserId")
                               .MapRightKey("GroupId")
                               .ToTable("SecondaryGroupAssignments"));
    }
}
3 голосов
/ 01 октября 2013

Основываясь на превосходном ответе Ладислава, вот как это сделать без использования каких-либо отображений - только атрибуты, примененные к самим классам модели:

public class Group 
{
    public int Id { get; set; }

    [MaxLength(300)]
    public string Name { get; set; }

    public ICollection<User> Users { get; set; }
}

public class User
{
    public int Id { get; set; }

    [MaxLength(300)]
    public string Name { get; set; }

    [ForeignKey("PrimaryGroup")]
    public int PrimaryGroupId { get; set; }
    [Required]
    public Group PrimaryGroup { get; set; }

    [InverseProperty("Users")]
    public ICollection<Group> SecondaryGroups { get; set; }
}

Примечания * * 1004 Если хотите, вы можете добавить виртуальное ключевое слово к 2 ICollection с и Group. Это позволяет ленивую загрузку . По производительности я не рекомендую, но это возможно. Я включил MaxLength атрибуты с произвольной (но безопасной) длиной 300, потому что при выводе строк в EF без MaxLength вы получаете низкоэффективные столбцы NVarChar(MAX). Совершенно не имеет отношения к тому, что просят, но лучше опубликовать хороший код. Я рекомендую использовать имена классов "Пользователь" и "Группа" для ваших классов EF. Они усложнят любой SQL-запрос, который вы попытаетесь запустить позже, и для доступа к ним придется ввести [User] и [Group], а также усложнить использование этих классов в контроллерах MVC, где ваш класс User будет конфликтовать со свойством Context User, который дает вам доступ к библиотеке Asp.Net Identity.

...