查询的结果从实体框架查询返回相同的 COLUMN_NAME 值,这没有意义

Posted

技术标签:

【中文标题】查询的结果从实体框架查询返回相同的 COLUMN_NAME 值,这没有意义【英文标题】:The result of a query returns the same value for COLUMN_NAME from an Entity Framework query, which doesn't make sense 【发布时间】:2021-06-22 13:55:07 【问题描述】:

我已经为这个问题苦苦挣扎了好几天。一位同事针对他也创建的 SQL Server 视图编写了一个 LINQ 查询,该视图返回 18 行作为他正在过滤的表名。

他创建的视图使用了系统视图INFORMATION_SCHEMA。奇怪的是,当 LINQ 查询返回结果时,COLUMN_NAME 的所有值都是ID

但是,当我针对同一个视图运行SELECT 时,所有COLUMN_NAMES 都不同。我不明白为什么会有差异。

这是 SQL Server 视图:

CREATE view [Core].[vwDataDictionary] 
AS
    SELECT 
        ROW_NUMBER() OVER(order by A.[TABLE_CATALOG]) AS [ID]   
        ,A.[TABLE_CATALOG]
        ,A.[TABLE_SCHEMA]
        ,A.[TABLE_NAME]
        ,A.[COLUMN_NAME]
        ,[ORDINAL_POSITION]
        ,[COLUMN_DEFAULT]
        ,[IS_NULLABLE]
        ,[DATA_TYPE]
        ,[CHARACTER_MAXIMUM_LENGTH]
        ,[CHARACTER_OCTET_LENGTH]
        ,[NUMERIC_PRECISION]
        ,[NUMERIC_PRECISION_RADIX]
        ,[NUMERIC_SCALE]
        ,[DATETIME_PRECISION]
        ,[CHARACTER_SET_CATALOG]
        ,[CHARACTER_SET_SCHEMA]
        ,[CHARACTER_SET_NAME]
        ,[COLLATION_CATALOG]
        ,[COLLATION_SCHEMA]
        ,[COLLATION_NAME]
        ,[DOMAIN_CATALOG]
        ,[DOMAIN_SCHEMA]
        ,[DOMAIN_NAME]
        ,B.[CONSTRAINT_NAME]
        ,C.[CONSTRAINT_TYPE]
    FROM 
        [INFORMATION_SCHEMA].[COLUMNS] AS A
    LEFT JOIN 
        [INFORMATION_SCHEMA].[CONSTRAINT_COLUMN_USAGE] AS B ON A.TABLE_NAME = B.TABLE_NAME 
                                                            AND A.COLUMN_NAME = B.COLUMN_NAME
    LEFT JOIN
        [INFORMATION_SCHEMA].[TABLE_CONSTRAINTS] AS C ON B.CONSTRAINT_NAME = C.CONSTRAINT_NAME
    WHERE 
        A.[TABLE_SCHEMA] = 'App'

他倾向于声明一个全局 DbContext 来使用。我认为这是问题所在,所以我只稍微更改了代码以使用本地 DbContext。不幸的是,这并没有帮助,因为我所做的更改与他的代码所做的相同。

只有这个区别,其余的 C# 代码是他的:

using (var ctx = new CoreFrameworkEntities())

    var dd_fields_query = ctx.vwDataDictionaries.Where(d => d.TABLE_NAME == CurrentTableName);
    var dd_fields_query_list = dd_fields_query.ToList();

    foreach (var item in dd_fields_query_list)
    
        string col_name = "";

        foreach (var camel in SplitCamelCase(item.COLUMN_NAME))
        
            col_name = col_name + camel + " ";
        

        col_name = col_name.Replace("_", "").Trim();

        if (item.COLUMN_NAME == "ID")
        
            col_name = "ID";
        
        else if (item.COLUMN_NAME == "InstrumentID")
        
            col_name = "Instrument ID";
        
        else if (item.COLUMN_NAME.EndsWith("ID"))
        
            col_name = item.COLUMN_NAME.Split('I')[0] + " ID";
        

        KeyValuePair<vwDataDictionary, string> kvp = new KeyValuePair<vwDataDictionary, string>(item, col_name);
        TableFields.Add(kvp);
    

这是我写的SELECT,用于将结果与 LINQ 查询产生的结果进行比较:

SELECT * 
FROM Core.vwDataDictionary
WHERE TABLE_NAME = 'Proficiency'

那么,为什么 LINQ 查询返回 18 行,所有的值都为“ID”,而 SELECT 返回 18 行,所有的列名都是正确的 Proficiency 表?

【问题讨论】:

你需要左外连接吗? 从 LINQ 查询传输的 SQL 查询是什么?考虑使用 LINQPad 来调试查询。运行该 SQL 查询的结果是什么? @jdweng 该视图有一个LEFT JOIN? @NetMage : 如果右边为空怎么办? 我不知道为什么 SQL 视图使用 LEFT JOIN。 @NetMage 关于使用 LINQPad 的好建议。我现在就试试看。 【参考方案1】:

从实体框架中使用时,views 存在一个微妙的问题。

如果你有一个带有 EF 的表,你需要有一个主键来唯一标识每一行。通常,这是一个单列,例如ID 或类似的东西。

对于视图,您没有“主键”的概念 - 视图仅包含来自某些表的一些列。

因此,当 EF 映射视图时,它找不到主键 - 因此,它将使用视图中的所有不可为空的列作为“替代”主键。

当 EF 现在读取数据时,它将获取所有列并创建一个表示该行的内存对象。如果 EF 现在稍后从数据库中读取另一行 构成视图的 替代 PK 的那些不可为空的列是相同的 - 那么它会认为: “哎呀,我已经有了那一行”,只需将同一对象的另一个副本添加到您的结果集中。

因此,在这种情况下,最终您的 EF 结果集 中可能会有 18 个相同的行 - 即使 SQL Server 输出正确显示不同的数据。 ......

更新: 作为一种可能的解决方案,您可以尝试点击提供“更好”列的 sys.columnssys.tables 目录视图 - 不可为空的列,但并非全部每列都一样....

试试这样的:

CREATE VIEW [Core].[vwDataDictionary] 
AS
    SELECT 
        t.Name,
        t.object_id,
        c.Name,
        c.column_id
        -- possibly later more columns here....
    FROM
        sys.tables t
    INNER JOIN
        sys.columns c ON c.object_id = t.object_id

【讨论】:

这很有意义。我们依赖于那个 SQL 视图,那么我们如何使用 EF 解决这个问题呢? 其实SQL View 的第一行不应该是这样吗? ROW_NUMBER() OVER(order by A.[TABLE_CATALOG]) AS [ID] 我刚刚尝试在 ID 属性上添加 [Key] 数据注释。我将 ID 从可为空的 long 更改为 long。然后我从 TABLE_NAME 属性中删除了 [Key] 属性。这终于奏效了!!!我要感谢大家的反馈。你们都向我展示了解决这个问题所需的方向。 顺便说一句,我想我可能知道为什么它现在突然开始引起问题,而之前不是。我们曾经使用 EF 的 EDMX 文件。 (我们正在使用 EF 6。)我一直在将我们从 EDMX 转移到代码优先。因此,EF 生成的模型类可能做了它认为最适合给定 SQL 视图的事情。通过在 ID 上添加 [Key] 属性(并将其从 TABLE_NAME 中删除),我告诉它应该将什么视为主键。 @Rod:这听起来很合理,确实。很高兴你能解决这个问题!

以上是关于查询的结果从实体框架查询返回相同的 COLUMN_NAME 值,这没有意义的主要内容,如果未能解决你的问题,请参考以下文章

Spring Data JPA 查询结果返回至自定义实体

从数据库中检索到的实体与查询中的情况相同

使用实体框架时是不是可以从查询中返回字符串值?

WHERE DATE_COLUMN = '9999-12-31' 语句导致查询不返回任何结果

生成的查询在实体框架的版本之间是不同的

从实体框架查询返回的两个 List<> 对象的外连接