Entity Framework CTP5 Code-First: отображение класса с несколькими коллекциями другого класса - PullRequest
5 голосов
/ 21 февраля 2011

С EF CTP5 Code-First я пытаюсь отобразить модель класса, которая содержит несколько коллекций в одном классе, указывающих на другой класс.Вот пример того, что я имею в виду:

public class Company
{
    public int CompanyId { get; set; }
    public IList<Person> FemaleEmployees { get; set; }
    public IList<Person> MaleEmployees { get; set; }
}

public class Person
{
    public int PersonId { get; set; }
    public Company Company { get; set; }
}

Если я разрешаю создание базы данных из этой модели с DbContext без дальнейшей настройки, например:

public class MyContext : DbContext
{
    public DbSet<Company> Companies { get; set; }
    public DbSet<Person> People { get; set; }
}

..Затем я получаю две таблицы в SQL Server: простую таблицу Companies с одним столбцом CompanyId и таблицу People со следующими столбцами («FKRN» означает «Имя отношения с внешним ключом», как оно создано EF вSQL Server):

PersonId            int     not nullable
CompanyCompanyId    int     nullable       FKRN: Company_FemaleEmployees
CompanyCompanyId1   int     nullable       FKRN: Company_MaleEmployees
CompanyCompanyId2   int     nullable       FKRN: Person_Company

Последние три столбца имеют отношение внешнего ключа к первичному ключу CompanyId таблицы Companies.

Теперь у меня есть несколько вопросов:

  • 1) Почему я получаю три столбца внешнего ключа в таблице People?Я действительно ожидал двух.Если я удаляю свойство public Company Company { get; set; } из Person, третий столбец CompanyCompanyId2 исчезает, но я также теряю свойство ссылки в классе.

  • 2) Допустим, я отбрасываюCompany свойство из таблицы Person (оно мне не нужно в моей модели).Есть ли способ присвоить двум оставшимся столбцам внешнего ключа другое имя, чем автоматически созданные CompanyCompanyId и CompanyCompanyId1?(Например, FCompanyId и MCompanyId, чтобы указать отношение к коллекциям FemaleEmployees и MaleEmployees.)

  • 3) Есть ли способ определить эту модель только содин внешний ключ CompanyId в таблице People?Конечно, мне нужен дифференцирующий дополнительный столбец в классе Person (например, bool IsFemale).Person является либо частью коллекции FemaleEmployees, либо MaleEmployees, но никогда не включается в обе (естественно, в этом примере), поэтому с помощью SQL я мог бы получить эти коллекции по типу WHERE IsFemale = true/false AND CompanyId = 1.Мне интересно, могу ли я дать EntityFramework подсказку для загрузки двух коллекций таким образом.(Здесь я хотел бы не расширять модель классами FemalePerson и MalePerson, которые оба являются производными от Person в качестве базового класса, а затем используют, например, отображение Table-Per-Hierarchy, поскольку эти производные классы будут пустымии искусственный и не имел никакой другой цели, кроме включения сопоставления с SQL Server.) Наличие только одного внешнего ключа CompanyId позволило бы мне сделать его non-nullable, что невозможно с двумя внешними ключами (оба никогда не могут быть ненулевымив той же строке).

Спасибо за отзывы и предложения заранее!

Ответы [ 2 ]

3 голосов
/ 16 марта 2011
  • На вопрос (1): EF не может сопоставить одно ссылочное свойство Company в классе Person с двумя разными конечными точками сбора FemaleEmployees и MaleEmployees в классе Company одновременно. Соглашения о отображении предполагают, что на самом деле в Company существует третья конечная точка, которая не представлена ​​в модели. Поэтому создается третий внешний ключ.

  • На вопрос (2): С помощью кандидата на выпуск EF 4.1 теперь можно задавать имя внешнего ключа для столбца базы данных в Fluent API (что было невозможно с EF CTP5 ) с использованием метода Map класса ForeignKeyNavigationPropertyConfiguration:

    modelBuilder.Entity<Company>()
                .HasMany(c => c.FemaleEmployees)
                .WithOptional()
                .Map(conf => conf.MapKey("FCompanyId"))
                .WillCascadeOnDelete(false);
    
    modelBuilder.Entity<Company>()
                .HasMany(c => c.MaleEmployees)
                .WithOptional()
                .Map(conf => conf.MapKey("MCompanyId"))
                .WillCascadeOnDelete(false);
    
  • На вопрос (3): Я до сих пор не знаю.

Редактировать

Просто чтобы закрыть этот старый вопрос сейчас: (3) (связывание двух навигационных свойств в одном объекте с одной и той же конечной точкой другого объекта) невозможно, например: Код структуры конкретного объекта Сначала сопоставление модели «многие ко 2» ... (и я помню много других вопросов, которые безуспешно искали решение для такого сценария)

2 голосов
/ 23 февраля 2011

Я думаю, вы могли бы сделать это:

public class Company
{
    public int CompanyId { get; set; }
    public ICollection<Person> Employees { get; set; }
    public IEnumerable<Person> MaleEmployees {
        get
        {
            Employees.Where(x=> !x.IsFemale);
        }
    }
}

public class Person
{
    public int PersonId { get; set; }
    public Company Company { get; set; }
}

У вас есть только один CompanyID FK в таблице People.

Вы можете загружать сотрудников-мужчин, используя контекст EF:

context.Entry(companyInstance)
    .Collection(p => p.Employees)
    .Query()
    .Where(u => !u.IsFemale)
    .Load();

Я думаю, что ваш подход не очень хорош, потому что, что происходит, когда я добавляю мужчину в Company.FemaleEmployees?EF не знает эти правила

...