Entity Framework 4允许使用可空外键吗?

7
我有一个在Entity Framework实体中更新外键的问题。我使用自跟踪实体,并且有一个带有一些关系的实体,其中外键也作为属性存在(EF4的新功能之一)。该键(一个整数)被标记为可为空和并发模式固定。
具体来说,我有一个警报实体与确认用户之间的多对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

在我的自我跟踪实体中,确认用户ID被自动生成为可为空的,这正如预期的那样。然而,如果我将用户分配给已经持久化的警报并运行ApplyChanges,则自我跟踪上下文扩展会尝试在EF上下文中设置原始值(null)(在上下文扩展的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乐观并发机制的一部分,在此机制中,标记为“fixed”并发模式的属性的原始值将与数据库中的属性再次进行检查)。
在EF的自跟踪实体中,可空外键/基元类型是否得到充分支持?
如果没有,则必须使用虚拟实体代替null,或者是否有其他解决方法?
更新 我已尝试使用非STE重现问题,但是普通EF似乎可以很好地处理可空外键的乐观并发,因此这是一个STE问题,而不是EF问题。 自跟踪实体存在许多问题,因此在此处出现故障并不奇怪。如果我找到可以在STE T4脚本中实现的解决方法,我将在此发布。
2个回答

1

Bill Huth在MSDN上发布了一个可用的补丁。


0

是的,可空外键肯定是允许的。我们在很多地方都使用它们。你没有展示你的数据库或模型,所以很难确定问题可能是什么,但听起来好像实体框架无法找出其中一个表的主键。也许你没有一个主键,可能是因为其中一个是视图?我在这里猜测,因为你没有提供太多关于你正在做什么的信息。


可空的 int 列应该在你的 CSDL 中表示为 int?,而不是 int。尝试使用一个新的(之前未映射的)表格;你会看到区别的。自从你创建模型以来,你改变了 nullability 吗? - Craig Stuntz
顺便问一下,你是否正在使用带有并发检查的自跟踪实体?当自跟踪实体上下文扩展填充带有固定并发模式标记的可空整数时,就会出现问题。如果您没有使用并发模型或自跟踪实体,则可能不会遇到此问题。 - Holstebroe
Type="Int32" Nullable="true" 是我在写“int?”时的意思。这应该被生成为 int?。固定并发可能不适用于随机FK;我们使用 TIMESTAMP 字段来解决此问题。 - Craig Stuntz
可空的Int32在STE中被映射为Nullable<Int32>,正如预期的那样。STE按预期处理了可空值,但当将一个null值和一个非null值进行赋值时,null值会被存储在原始值集合中。然而,STE未能将null值注入到EF上下文作为原始值,这导致EF在进行乐观并发检查时使用零而不是null。 - Holstebroe
是的,问题在于entityClrType.GetGenericTypeDefinition()返回的是Int32类型而不是可空类型。这与STE包装存在冲突,后者正确地将外键定义为Nullable<Int32>。 - Holstebroe
显示剩余9条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接