Entity Framework Code Чувствительность к первому регистру на строковых отношениях PK/FK
У меня есть довольно простое составное отношение один ко многим, определенное с использованием POCO/Fluent API, один столбец которого является строкой.
Я обнаружил, что данные в этом столбце в нашей базе данных являются несовместимыми с точки зрения случая, то есть "abb", "ABB" - это наша основная система ERP и снабжается различными источниками, которые в основном находятся вне нашего контроля.
Это приводит к проблемам с использованием кода EF в первую очередь при присоединении к связанным таблицам, так как EF беззвучно игнорирует объединение, когда случай PK/FK отличается, даже если SQL Profiler показывает правильный выполняемый SQL и возвращаемые результаты.
Я использую WCF, поэтому отложенная загрузка и создание прокси отключены, и я с нетерпением жду загрузки необходимых связанных сущностей с помощью Include. например.
var member = context.Member.Include(m => m.Audits).First(m => m.Id == id);
Есть ли какие-либо решения для этого помимо внесения изменений в схему базы данных?
2 ответа
EF нечувствительное сравнение соединений
Привет у меня та же проблема (хотя не с остроумием код сначала, но с сгенерированной моделью)
Причина в том, что EF производит сравнение ключевых полей с учетом регистра и не находит связанных объектов.
Я предполагаю, что проблема кроется в "Менеджере отношений EDM" и, возможно, есть возможность переопределить это поведение.
Я нашел простой обходной путь для этого: нижний регистр связанных свойств:
[EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)]
[DataMemberAttribute()]
public global::System.String id
{
get
{
return _id.ToLower(); // **<- here**
}
set
{
if (_id != value)
{
OnidChanging(value);
ReportPropertyChanging("id");
_id = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("id");
OnidChanged();
}
}
}
private global::System.String _id;
partial void OnidChanging(global::System.String value);
partial void OnidChanged();
Это на самом деле работает, но, конечно, это слабое решение. Я придерживаюсь этого на некоторое время, поскольку я (или кто-то другой) предлагает лучшее решение.
Удачи!
Я нашел обходной путь, который вручную "зашивает" связь после того, как контекст извлек соответствующие строки из базы данных. В переводе на вашу проблему это будет примерно так:
//Your original query
var members = context.Member.Include(m => m.Audits).First(m => m.Id == id);
//The "stitch up" code that should probably be moved to a method of the data context.
var membersWithoutAudits = context.Members.Local.Where(m => !m.Audits.Any()).ToList();
foreach (var nextMember in membersWithoutAudits) {
//Now we can populate the association using whatever logic we like
nextMember.Audits = context.Audits.Local.Where(a => a.MemberId.ToLower() == nextMember.Id.ToLower()).ToList();
}
Обратите внимание, как мы используем контекст.[DbSet].Локальное свойство, чтобы гарантировать, что мы делаем все "зашивание" в памяти без каких-либо дальнейших вызовов SQL. Я также выбираю участников без аудитов в качестве оптимизации производительности, чтобы мы не переоценивали работу ассоциации EF (в тех случаях, когда она работала). Но вы можете так же легко переназначить каждый "член" экземпляр.