7

我在更新实体框架实体中的外键时遇到问题。我正在使用自我跟踪实体,并且有一个具有某些关系的实体,其中外键也作为属性存在(EF4 的新功能之一)。键(一个整数)被标记为 Nullable 和 Concurrency Mode fixed。

具体来说,我有一个与确认用户具有多对 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 会自动生成为 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 脚本中实现的解决方法,我将在此处发布。

4

2 回答 2

1

Bill Huth 在MSDN上发布了一个工作补丁。

于 2010-11-02T15:47:01.830 回答
0

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

于 2010-08-30T15:21:34.113 回答