У меня проблема с обновлением внешнего ключа в сущности Entity Framework. Я использую объекты с самопроверкой и имею объект с некоторыми отношениями, в которых внешний ключ также присутствует как свойство (одна из новых функций EF4). Ключ (целое число) помечен как Nullable и фиксированный режим параллелизма.
В частности, у меня есть объект Alarm с отношением многие к 0..1 к подтверждающему пользователю. (пользователь может подтвердить несколько тревог, но тревогу может подтвердить только ноль или один пользователь).
Определения сущностей (упрощенные):
Alarm properties
Id Int32 non-nullable identity entity key
UserId Int32 nullable concurrency mode fixed
Alarm navigation properties
User 0..1 multiplicity
User properties
Id Int32 non-nullable identity entity key
Name String non-nullable
В моей сущности с самотслеживанием подтверждающий идентификатор пользователя автоматически генерируется как Nullable, как и ожидалось, однако, если я назначаю пользователю уже постоянный сигнал тревоги и запускаю ApplyChanges, расширение контекста самотслеживания пытается установить исходное значение (null) в контекст EF (в SetValue в расширениях контекста), но молча пропускает это, потому что ClrEquivalentType из EdmType не допускает значения NULL Int32.
Автоматически сгенерированный код расширения:
private static void SetValue(this OriginalValueRecord record, EdmProperty edmProperty, object value)
{
if (value == null)
{
Type entityClrType = ((PrimitiveType)edmProperty.TypeUsage.EdmType).ClrEquivalentType;
if (entityClrType.IsValueType &&
!(entityClrType.IsGenericType && typeof(Nullable<>) == entityClrType.GetGenericTypeDefinition()))
{
// Skip setting null original values on non-nullable CLR types because the ObjectStateEntry won't allow this
return;
}
}
int ordinal = record.GetOrdinal(edmProperty.Name);
record.SetValue(ordinal, value);
}
Когда позже EF пытается обновить мой аварийный сигнал, я получаю исключение OptimisticConcurrencyException, потому что он создает предложение WHERE в операторе UPDATE, где он использует 0 (ноль) в качестве исходного значения внешнего ключа пользователя вместо правильного «равно нулю». (Предложение WHERE является частью механизма оптимистичного параллелизма EF, в котором исходные значения свойств, отмеченных «фиксированным» режимом параллелизма, проверяются по свойствам в базе данных).
Внешние ключи / примитивные типы, допускающие значение NULL, не полностью поддерживаются в объектах самопроверки для EF? Если нет, должен ли я использовать фиктивные сущности вместо null или есть другие обходные пути?
Обновление. Я попытался воспроизвести проблему без STE, но простой EF, похоже, хорошо справляется с оптимистичным параллелизмом для внешних ключей, допускающих значение NULL, так что это проблема STE, а не EF. Существует множество проблем с объектами самопроверки, поэтому неудивительно, что здесь есть сбой. Если я найду обходной путь, который можно реализовать в сценарии STE T4, я опубликую его здесь.