Entity Framework 4.1 Fluent сопоставление внешнего ключа и внешнего объекта со строковым ключом

Я перехожу от сопоставления EDMX к сопоставлению DbContext и Fluent EF 4.1, и я хочу сопоставить как внешний ключ строки, так и внешний объект, используя свободный API. У меня есть сотрудник с дополнительным офисом. Я хотел бы иметь как OfficeId, так и объект Office в классе Employee (все это доступно только для чтения, и мне не нужно сохранять эти объекты). Объекты с ключами int работают нормально, но я попробовал несколько со строковыми ключами и получил тот же результат — поле OfficeId заполняется, но объект Office возвращается как null. Проверка в профилировщике SQL: данные запрашиваются, но офисный объект не заполняется.

public partial class Employee
{
    public int Id { get; set; }
    // snip irrelevant properties
    public Office Office { get; set; }  // this is (incorrectly) always null
    public string OfficeId { get; set; }
    public WorkGroup WorkGroup { get; set; } // this one with the int key is fine
    public int? WorkGroupId { get; set; }
    // snip more properties
}

public partial class Office
{
    public string Id { get; set; }
    public string Description { get; set; }
}

public partial class WorkGroup
{
    public int Id { get; set; }
    public string Code { get; set; }
}

После отзыва от Ладислава, приведенного ниже, я сопоставляю это так в OnModelCreating.

modelBuilder.Entity<Employee>().HasKey(d => d.Id).ToTable("Employee", "ExpertQuery");
modelBuilder.Entity<Office>().HasKey(d => d.Id).ToTable("Office", "ExpertQuery");
modelBuilder.Entity<WorkGroup>().HasKey(d => d.Id).ToTable("WorkGroup", "ExpertQuery");

modelBuilder.Entity<Employee>()
    .HasOptional(a => a.Office)
    .WithMany()
    .Map(x => x.MapKey("OfficeId")); // this one does not work
modelBuilder.Entity<Employee>()
            .HasOptional(e => e.WorkGroup)
            .WithMany()
            .HasForeignKey(e => e.WorkGroupId); // this one works fine

Я предполагаю, что есть какая-то тонкость со строковыми ключами, которую мне не хватает? Я запрашиваю его следующим образом:

var employees = expertEntities.Employees.Include("Office").Include("WorkGroup").Take(10).ToList();

Если я опущу поле OfficeId из Employee и настрою сопоставление следующим образом:

modelBuilder.Entity<Employee>()
    .HasOptional(e => e.BusinessEntity)
    .WithMany()
    .Map(x => x.MapKey("OfficeId"));

Затем объект office заполняется, но мне нужно поле OfficeId в объекте Employee.


person MarkGr    schedule 25.09.2011    source источник


Ответы (3)


Что ж, я обнаружил проблему - это проблема с данными - значения строки первичного ключа были дополнены пробелами, а значения внешнего ключа - нет (!). Хотя SQL правильно объединяет таблицы (игнорируя заполнение) и извлекает правильные данные, похоже, что EF не будет сопоставлять их обратно с правильными объектами, поскольку .NET более суетлив, чем SQL, в отношении конечных пробелов.

person MarkGr    schedule 26.09.2011

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

person kroonwijk    schedule 25.09.2011
comment
Спасибо, это помогло мне уточнить ситуацию - клавиши int работают нормально, но строковые клавиши, похоже, не работают. Я добавил несколько из каждого для проверки, и с ключами int все в порядке, а строковые ключи всегда дают нулевой объект. - person MarkGr; 26.09.2011

Это не правильное отображение. Если у вас есть свойство FK, вы не можете использовать Map и MapKey. Это для сценариев, в которых у вас нет этого свойства. Попробуй это:

modelBuilder.Entity<Employee>()
            .HasOptional(a => a.Office)
            .WithMany()
            .HasForeignKey(a => a.OfficeId);

Также первая часть вашего сопоставления с сопоставлением объектов с таблицей, скорее всего, неверна. Map используется для сценариев наследования и разделения сущностей. Вы ищете ToTable:

modelBuilder.Entity<Employee>().HasKey(d => d.Id).ToTable("ExpertQuery.Employee");

Также, если ваш ExpertQuery является схемой базы данных, а не частью имени таблицы, он должен выглядеть так:

modelBuilder.Entity<Employee>().HasKey(d => d.Id).ToTable("Employee", "ExpertQuery");
person Ladislav Mrnka    schedule 25.09.2011
comment
Спасибо, я исправил отображение, как вы предложили. Объекты находятся в схеме, к сожалению, моя проблема все еще остается. Если я изменю сопоставление на .HasForeignKey, поле OfficeId будет заполнено, но объект Office вернется к нулю (я сделал это .Include). Нотация .Map работает, если я удалю поле OfficeId, и тогда я смогу получить объект Office. Я обнаружил, что мне нужно сделать .Map, так как ключ называется OfficeId, а не Office_Id в базе данных. - person MarkGr; 26.09.2011