Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Entity framework 实体框架4中是否允许使用可为空的外键?_Entity Framework_Nullable_Self Tracking Entities_Optimistic Concurrency - Fatal编程技术网

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

Entity framework 实体框架4中是否允许使用可为空的外键?,entity-framework,nullable,self-tracking-entities,optimistic-concurrency,Entity Framework,Nullable,Self Tracking Entities,Optimistic Concurrency,我在更新实体框架实体中的外键时遇到问题。我使用的是自跟踪实体,并且有一个实体具有一些关系,其中外键也作为属性存在(EF4的新特性之一)。键(一个整数)被标记为可为null,并发模式已修复 具体来说,我有一个报警实体,与确认用户有多对0..1关系。(一个用户可以确认多个报警,但一个报警只能由零个或一个用户确认) 实体定义(简化): 在我的自跟踪实体中,正如预期的那样,确认用户id自动生成为可空,但是如果我将用户分配给已经持续的报警并运行ApplyChanges,自跟踪上下文扩展将尝试在EF上下文中

我在更新实体框架实体中的外键时遇到问题。我使用的是自跟踪实体,并且有一个实体具有一些关系,其中外键也作为属性存在(EF4的新特性之一)。键(一个整数)被标记为可为null,并发模式已修复

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

实体定义(简化):

在我的自跟踪实体中,正如预期的那样,确认用户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);
    }
private static void SetValue(此原始值记录、EdmProperty、EdmProperty、对象值)
{
如果(值==null)
{
类型entityClrType=((PrimitiveType)edmProperty.TypeUsage.EdmType).ClrEquivalentType;
如果(entityClrType.IsValueType&&
!(entityClrType.IsGenericType&&typeof(可空)=entityClrType.GetGenericTypeDefinition())
{
//跳过在不可为null的CLR类型上设置null原始值,因为ObjectStateEntry不允许这样做
返回;
}
}
int ordinal=record.GetOrdinal(edmProperty.Name);
记录.设置值(序号,值);
}
当EF稍后尝试更新我的报警时,我得到一个OptimisticConcurrencyException,因为它在update语句中构造了一个WHERE子句,其中使用0(零)作为原始用户外键值,而不是正确的“is null”。(WHERE子句是EF乐观并发机制的一部分,其中标记为“固定”并发模式的属性的原始值将在数据库中的属性中进行检查)

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

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

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

比尔·胡斯在上发布了一个工作补丁。

我很确定我的主键是正确的。当我将可为空的引用实体更改为新实体时,就会出现问题。这将导致原始实体引用(null)和键(null)存储在原始值集合中。调用ApplyChanges时,尝试将原始值从entities change tracker移动到EF上下文,但由于EF上下文将键的类型定义为Int32且不可作为自跟踪实体为null,因此不能将其分配为null。可为null的int列应作为
int?
而不是
int
在CSDL中。使用新的(以前未映射的)表进行尝试;你会看到的。自从创建模型以来,您是否更改了可空性?我尝试创建一个没有主键的新实体“FooEntity”,以及一个名为Foo的可空Int32。这是在CSDL中生成的:没有Int32?在这里将Int32更改为Int32?引起错误根据其数据类型“顺便说一句,您是否使用带有并发检查的自跟踪实体”,值“Int32”无效?当自跟踪实体上下文扩展使用标记为固定并发模式的可空整数填充上下文时,就会出现问题。如果您不使用并发模型或自跟踪实体,您可能不会遇到问题。
Type=“Int32”Nullable=“true”是我写“int”时的意思。应将其编码为
int?
。固定并发可能不适合随机FK;为此,我们使用一个
TIMESTAMP`字段。
    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);
    }