EF SqlQuery尝试映射对象属性,即使它归因于[NotMapped]

时间:2017-08-16 13:34:04

标签: c# entity-framework

我有一个用context.Database.SqlQuery<MyObject>("MyProc")

执行的存储过程

MyObject有一个只读属性:

[NotMapped]
public bool IsSomething { get { return this.otherproperty == "something"; } }

所以我收到错误:

  

System.IndexOutOfRangeException:IsSomething   在System.Data.ProviderBase.FieldNameLookup.GetOrdinal等

这是因为MyProc在结果列中没有IsSomething(我100%肯定可能是原因)。

它不应该忽略它,因为它[NotMapped]?我是否需要为SqlQuery设置其他内容?

为了让事情变得更加奇怪,我只能在生产中看到它,从Stackify的日志中看,并且页面似乎正确加载而浏览器没有任何错误。

2 个答案:

答案 0 :(得分:4)

根据documentation

  

Database.SqlQuery<TElement> Method (String, Object[])

     

创建一个原始SQL查询,该查询将返回给定泛型类型的元素。 类型可以是任何类型,其属性与查询返回的列的名称相匹配,也可以是简单的基本类型。该类型不必是实体类型。即使返回的对象类型是实体类型,也不会被上下文跟踪此查询的结果.....

强调我的

它正在查看错误消息中IsSomething指示的System.Data.ProviderBase.FieldNameLookup.GetOrdinal查询返回的读者。

由于该列不存在,您将获得IndexOutOfRangeException

  

它不应该忽略它,因为它是[NotMapped]

没有。它忽略对象上存在的任何属性,包括[NotMapped]。请参阅上面引用的引用

  

我是否需要为SqlQuery设置其他内容?

我建议创建另一个对象,其中只有属性匹配/映射到过程的预期结果,并将其用作SqlQuery调用的泛型参数。

答案 1 :(得分:2)

  

为了让事情变得更加奇怪,我只在生产中看到它,从Stackify的日志中看,并且页面似乎正确加载而没有任何错误

我不熟悉Stackify日志,但根据我对EF6的了解,我会推测并说这是误报日志。

在这方面,文件并不十分清楚。首先,实体和非实体SqlQuery结果类型由不同的代码分支处理。虽然两个翻译都使用CLR属性名作为列名(即不考虑实体类型的列名映射),但实体类型的忽略(NotMapped)属性确实是按预期从结果中排除

此外,有问题的IndexOutOfRangeException被EF代码捕获并转换为其他异常(EntityCommandExecutionException),可以从相关方法的source code GetMemberOrdinalFromReader中看到}:

// <summary>
// Given a store datareader and a member of an edmType, find the column ordinal
// in the datareader with the name of the member.
// </summary>
private static int GetMemberOrdinalFromReader(
    DbDataReader storeDataReader, EdmMember member, EdmType currentType,
    Dictionary<string, FunctionImportReturnTypeStructuralTypeColumnRenameMapping> renameList)
{
    int result;
    var memberName = GetRenameForMember(member, currentType, renameList);

    if (!TryGetColumnOrdinalFromReader(storeDataReader, memberName, out result))
    {
        throw new EntityCommandExecutionException(
            Strings.ADP_InvalidDataReaderMissingColumnForType(
                currentType.FullName, member.Name));
    }
    return result;
}

TryGetColumnOrdinalFromReader

// <summary>
// Given a store datareader and a column name, try to find the column ordinal
// in the datareader with the name of the column.
// </summary>
// <returns> true if found, false otherwise. </returns>
private static bool TryGetColumnOrdinalFromReader(DbDataReader storeDataReader, string columnName, out int ordinal)
{
    if (0 == storeDataReader.FieldCount)
    {
        // If there are no fields, there can't be a match (this check avoids
        // an InvalidOperationException on the call to GetOrdinal)
        ordinal = default(int);
        return false;
    }

    // Wrap ordinal lookup for the member so that we can throw a nice exception.
    try
    {
        ordinal = storeDataReader.GetOrdinal(columnName);
        return true;
    }
    catch (IndexOutOfRangeException)
    {
        // No column matching the column name found
        ordinal = default(int);
        return false;
    }
}

基于以上内容以及缺少具有真实异常的repro,我会说你可以安全地忽略该日志。