实体框架4是否允许使用可为空的外键?

实体框架4是否允许使用可为空的外键?

问题描述:

我在更新实体框架实体中的外键时遇到问题.我正在使用自我跟踪实体,并且有一个具有某些关系的实体,其中外键也作为属性存在(EF4的新功能之一).密钥(整数)被标记为Nullable并且并发模式已固定.

I have a problem updating a foreign key in an Entity Framework entity. I am using self tracking entities and have an entity with some relations where the foreign key is also present as a property (one of the new features of EF4). The key (an integer) is marked as Nullable and Concurrency Mode fixed.

具体来说,我有一个与确认用户具有许多到0..1关系的Alarm实体. (一个用户可以确认多个警报,但是一个警报只能由零个或一个用户确认.)

Specifically I have an Alarm entity with a many to 0..1 relationship to a confirming user. (a user may confirm several alarms, but an alarm can be confirmed by only zero or one users).

实体定义(简化):

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

在我的自我跟踪实体中,确认用户ID会像预期的那样自动生成为Nullable,但是,如果我将用户分配给已经存在的警报并运行ApplyChanges,则自我跟踪上下文扩展会尝试设置原始值( null)(在EF上下文中)(在上下文扩展中的SetValue中),但是由于EdmType的ClrEquivalentType是不可为null的Int32,因此无提示地跳过了这一点.

In my self tracking entity the confirming user id is auto-generated as a Nullable just as expected, however if I assign a user to an already persistent alarm and run ApplyChanges, the self tracking context extension tries to set the original value (null) in the EF context (In SetValue in the context extensions), but silently skips that because the ClrEquivalentType of the EdmType is a non-nullable 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,因为它在UPDATE语句中构造了WHERE子句,其中它使用0(零)作为原始用户外键值,而不是正确的"is null". (WHERE子句是EF乐观并发机制的一部分,其中将再次检查标记为固定"并发模式的属性的原始值,然后再检查数据库中的属性.)

When the EF later tries to update my alarm I get an OptimisticConcurrencyException because it constructs a WHERE clause in the UPDATE statement where it uses 0 (zero) as the original user foreign key value instead of the correct "is null". (The WHERE clause is part of the EF optimistic concurrency mechanism, where the original values of the properties marked with "fixed" concurrency mode are checked agains the properties in the database).

EF的自我跟踪实体中是否不完全支持可空的外键/原始类型? 如果不是,我是否被迫使用虚拟实体代替null还是有其他解决方法?

Are nullable foreign keys / primitive types not fully supported in self tracking entities for EF? If not, am I forced to use dummy entities instead of null or are there other workarounds?

更新 我曾尝试在没有STE的情况下重现该问题,但是纯EF似乎可以为可空外键很好地处理乐观并发,因此这是STE问题,而不是EF问题. 自我跟踪实体存在很多问题,因此在这里出现故障也就不足为奇了.如果我发现可以在STE T4脚本中实现的解决方法,则将其发布在这里.

Update I have tried to reproduce the problem without STE, but plain EF seems to handle optimistic concurrency well for nullable foreign keys, so this is an STE problem, not an EF problem. There is numerous issues with self tracking entities, so it is not surprising that there is a glitch here. If I find a workaround that can be implemented in the STE T4 script I will post it here.

Bill Huth在

Bill Huth posted a working patch at MSDN.