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

时间:2010-08-30 07:15:54

标签: entity-framework nullable self-tracking-entities optimistic-concurrency

我在更新Entity Framework实体中的外键时遇到问题。我正在使用自我跟踪实体并且具有一些具有某种关系的实体,其中外键也作为属性存在(EF4的新特征之一)。密钥(整数)标记为Nullable和并发模式已修复。

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

实体定义(简化):

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是一个不可为空的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乐观并发机制的一部分,其中标记为“固定”并发模式的属性的原始值将再次检查数据库中的属性。)

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

更新 我试图在没有STE的情况下重现这个问题,但普通的EF似乎很好地处理了可以为空的外键的乐观并发,所以这是一个STE问题,而不是EF问题。 自跟踪实体存在许多问题,因此这里存在故障并不奇怪。如果我找到可以在STE T4脚本中实现的解决方法,我将在此处发布。

2 个答案:

答案 0 :(得分:1)

Bi​​ll Huth在MSDN发布了一个工作补丁。

答案 1 :(得分:0)

是的,肯定允许可以为空的外键。我们到处都用它们。您没有显示您的数据库或模型,因此很难确定问题是什么,但听起来好像实体框架无法找出其中一个表的主键。也许你没有一个,也许是因为其中一个是观点?我在这里猜测,因为你没有提供有关你正在做什么的大量信息。