【问题标题】:Linq results different than the sql resultLinq 结果与 sql 结果不同
【发布时间】:2016-02-17 14:24:12
【问题描述】:

我有一个使用 LINQ 的 MVC4 Web 应用程序。

我有以下查询,它在 SQL 中产生 53 行。

    select * from table1 t join
    [table2] tpf on t.TestID=tpf.TestID
    join
     table3 pf on tpf.Test2ID =pf.Test2ID
    join table4 pfp on
    pf.Test3ID = pfp.Test3ID
     join table5 p on pfp.Test5ID = p.Test5ID  where t.testtypeid=1
     order by pfp.Test3ID,pf.Test2ID

如果我转换如下相同的查询,它会返回更多记录。

 trvm.MyTestVMs = (
    from tt in db.table1s
    join ttpf in db.table2s on tt.TestID equals ttpf.TestID                      
    join pf in db.table3s on ttpf.Test2ID equals pf.Test2ID

    join pfp in db.table4s on pf.Test3ID equals pfp.Test3ID
    join p in table5s on pfp.Test5ID equals p.Test5ID
    where tt.testtypeid == 1

    orderby pfp.Test3ID
    orderby pf.Test2ID 

    select new MyTestVM
    {
        FamilyID = pf.Test2ID,
        ProductID = p.Test3ID,
        Desc = p.Description
    }
).ToList();

从 SQL 和上述 LINQ 得到的结果各不相同。实际上,我从 LINQ 查询中得到了一些重复的结果。造成这种差异的原因是什么?

【问题讨论】:

  • 是数据库视图还是表?没有PK的表?
  • 只是表格。表中有主键
  • 修复你的order by子句,然后像这样改代码var query = ( ...);(没有ToList()调用),然后var sql = query.ToString(); trvm.ProductFamilyProductVMs = query.ToList();,放一个断点,看看sql变量包含一个SQL查询文本。如果是,请使用文本可视化工具打开它,将其复制并粘贴到问题中。
  • 用 sql 更新问题
  • 生成的 SQL 包含一些冗余(重复)连接,不确定是否是问题所在,您可以尝试在数据库中执行它(将 @p__linq... 替换为常量)并查看它是否返回正确数量的行与否。

标签: sql-server asp.net-mvc entity-framework linq entity-framework-6


【解决方案1】:

事实证明,由于使用了 products 查询变量(未在帖子中显示),LINQ 查询不等同于发布的 SQL 查询,这导致 many-to-many 链接表之一被包含两次,从而产生更多的记录。

解决此问题的一种方法是将products 替换为db.Products,并应用与您尝试重用的查询变量中相同的过滤器。

但是,如果您想重用查询变量,那么正确的方法是:

// Eliminate the need of DbFunctions.TruncateTime(dt) inside the queries
dt = dt.Date;

// Queries

var productFamilys = (
     from tt in db.TestTypes
     join ttpf in db.TestTypeProductFamilys on tt.TestTypeID equals ttpf.TestTypeID
     join pf in db.ProductFamilys on ttpf.ProductFamilyID equals pf.ProductFamilyID
     where tt.TestTypeID == TestTypeID
     where DbFunctions.TruncateTime(pf.StartDate) <= dt
     where DbFunctions.TruncateTime(pf.EndDate) > dt
     select pf
 );

var productFamilyProducts = (
    from pf in productFamilys
    join pfp in db.ProductFamilyProducts on pf.ProductFamilyID equals pfp.ProductFamilyID
    join p in db.Products on pfp.ProductID equals p.ProductID
    where DbFunctions.TruncateTime(p.StartDate) <= dt
    where DbFunctions.TruncateTime(p.EndDate) > dt
    select new { Family = pf, Product = p }
);

var products = (
    from pfp in productFamilyProducts
    select pfp.Product
);

var productFamilyProductVMs = (
    from pfp in productFamilyProducts
    orderby pfp.Product.ProductID, pfp.Family.ProductFamilyID
    select new ProductFamilyProductVM
    {
        ProductFamilyID = pfp.Family.ProductFamilyID,
        ProductID = pfp.Product.ProductID,
        ProdDesc = pfp.Product.Description
    }
);

// Results
trvm.ProductFamilys = productFamilys.ToList(); 
trvm.Products = products.ToList(); 
trvm.ProductFamilyProductVMs = productFamilyProductVMs.ToList();

现在最后一个查询(有问题的那个)的 SQL 看起来像这样

SELECT 
    [Project1].[ProductFamilyID] AS [ProductFamilyID], 
    [Project1].[ProductID] AS [ProductID], 
    [Project1].[Description] AS [Description]
    FROM ( SELECT 
        [Extent2].[ProductFamilyID] AS [ProductFamilyID], 
        [Extent4].[ProductID] AS [ProductID], 
        [Extent4].[Description] AS [Description]
        FROM    [dbo].[TestTypeProductFamilies] AS [Extent1]
        INNER JOIN [dbo].[ProductFamilies] AS [Extent2] ON [Extent1].[ProductFamilyID] = [Extent2].[ProductFamilyID]
        INNER JOIN [dbo].[ProductFamilyProducts] AS [Extent3] ON [Extent2].[ProductFamilyID] = [Extent3].[ProductFamilyID]
        INNER JOIN [dbo].[Products] AS [Extent4] ON [Extent3].[ProductID] = [Extent4].[ProductID]
        WHERE ([Extent1].[TestTypeID] = @p__linq__0) AND ((convert (datetime2, convert(varchar(255), [Extent2].[StartDate], 102) ,  102)) <= @p__linq__1) AND ((convert (datetime2, convert(varchar(255), [Extent2].[EndDate], 102) ,  102)) > @p__linq__2) AND ((convert (datetime2, convert(varchar(255), [Extent4].[StartDate], 102) ,  102)) <= @p__linq__3) AND ((convert (datetime2, convert(varchar(255), [Extent4].[EndDate], 102) ,  102)) > @p__linq__4)
    )  AS [Project1]
    ORDER BY [Project1].[ProductID] ASC, [Project1].[ProductFamilyID] ASC

即与示例 SQL 查询非常相似,应该产生相同的结果。

【讨论】:

    【解决方案2】:

    结果不同,因为在您的第二个查询中,您有两个“OrderBy”,因此,第二个 OrderBy 它适用于作为第一个“OrderBy”结果的集合,并且正在重新排序项目。 改变

         orderby pfp.ProductID
         orderby pf.ProductFamilyID 
    

    来自您在

    中的第二个查询
    orderby pfp.ProductID, pf.ProductFamilyID 
    

    得到相同的结果

    【讨论】:

    • 在这两个查询中,orderby 是相同的 orderby pfp.ProductID, pf.ProductFamilyID
    • 在我的第一个查询 order by 是 order by pfp.ProductID,pf.ProductFamilyID and in second order by pfp.ProductID orderby pf.ProductFamilyID。我需要在这里做出哪些改变
    • 我会试试的。但我想知道 order by 只是订购输出。如何获得更多的记录。
    • @jubi,让我们再试一次。我要问三个问题并得到其中一个的答案...在 Linq 返回的行中,是否有任何您不想返回的行,或者它们都是正确的,但与原始的 53 行重复?你得到多少?请尝试解决每个问题,因为它们会帮助我们帮助您。
    • 1) 它们是正确的,但与 origina 重复; 2)sql返回正确的53,linq返回有重复记录的73。对困惑感到抱歉。我已经用来自 sql server 的跟踪更新了这个问题。希望它能说明实际问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-19
    • 1970-01-01
    • 2018-11-28
    • 1970-01-01
    • 2020-08-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多