LINQ选择SQL视图得到错误的答案
我有一个SQL视图,它产生一个包含8列的响应。 它是一个相当复杂的,所以我不会在这里列出它,它不会增加我想要了解的问题。
当我使用此查询直接在SQL Manager中查询视图时
SELECT * FROM [GPPS].[dbo].[PartIndex] WHERE CategoryNameId = 182 AND CycleId = 13 AND BasketId = 304 AND MarketId = 8 ORDER BY ProductNameId
我得到了预期的结果(前两行很重要)
218 13 8 304 182 124 32575 162.84 218 13 8 304 182 124 32576 184.08 218 13 8 304 182 125 32577 156.13 218 13 8 304 182 127 32578 605.84 218 13 8 304 182 130 32579 141.51
当我对视图执行以下LINQ时
PartIndexes.Where(x => x.CategoryNameId == 182 && x.CycleId == 13 && x.BasketId == 304 && x.MarketId == 8) .ToList() .OrderBy(x => x.ProductNameId);
我真的得到了
218 13 8 304 182 124 32576 184.08 218 13 8 304 182 124 32576 184.08 218 13 8 304 182 125 32577 156.13 218 13 8 304 182 127 32578 605.84 218 13 8 304 182 130 32579 141.51
正如您所看到的,前两个条目是相同的,并且ID(32575和32576)的区别已丢失。
在视图上运行LINQ查询时查看SQL事件探查器会生成以下SQL
SELECT [Extent1].[SetNameId] AS [SetNameId], [Extent1].[CycleId] AS [CycleId], [Extent1].[MarketId] AS [MarketId], [Extent1].[BasketId] AS [BasketId], [Extent1].[CategoryNameId] AS [CategoryNameId], [Extent1].[ProductNameId] AS [ProductNameId], [Extent1].[PartId] AS [PartId], [Extent1].[Total] AS [Total] FROM (SELECT [PartIndex].[SetNameId] AS [SetNameId], [PartIndex].[CycleId] AS [CycleId], [PartIndex].[MarketId] AS [MarketId], [PartIndex].[BasketId] AS [BasketId], [PartIndex].[CategoryNameId] AS [CategoryNameId], [PartIndex].[ProductNameId] AS [ProductNameId], [PartIndex].[PartId] AS [PartId], [PartIndex].[Total] AS [Total] FROM [dbo].[PartIndex] AS [PartIndex]) AS [Extent1] WHERE (182 = [Extent1].[CategoryNameId]) AND (13 = [Extent1].[CycleId]) AND (304 = [Extent1].[BasketId]) AND (8 = [Extent1].[MarketId])
然后当我在SQL管理器中直接执行它时,我得到了所需的结果:
218 13 8 304 182 124 32575 162.84 218 13 8 304 182 124 32576 184.08 218 13 8 304 182 125 32577 156.13 218 13 8 304 182 127 32578 605.84 218 13 8 304 182 130 32579 141.51
任何人都知道这里可能会发生什么以及为什么执行LINQ请求会返回一个不同的结果,但是在执行LINQ查询生成的SQL时它会返回所需的结果?
当正确呈现时LINQ不直接使用时,SQL正在做什么?
您的问题与此类似: 使用没有主键的视图与实体
指定使您的行唯一的键。 您可以通过属性在实体映射上指定这些键:
public class YearlySalesOnEachCountry { [Key, Column(Order=0)] public int CountryId { get; set; } public string CountryName { get; set; } [Key, Column(Order=1)] public int OrYear { get; set; } public long SalesCount { get; set; } public decimal TotalSales { get; set; } }
或者你可以通过代码方法来做到这一点:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity() .HasKey(x => new { x.CountryId, x.OrYear }); }
如果entity framework为视图选择的键不唯一,则可能无法正确返回结果。 对于某些视图,无法定义正确的键(包含所有非空列),并且不会消耗视图。
对于这些情况,请考虑使用EF Edmx接口手动定义密钥,如下所示:
1) Any existing non-null field or 2) A separately added column "key" such as: select 1 as EfKey -- Must use with AsNoTracking()
两种方法都需要为每个查询( 链接 )使用“AsNoTracking()”。
使用AsNoTracking()信号EF绕过其基于密钥的记录缓存机制。 如果没有AsNoTracking(),结果可能会损坏,包含重复的行。
使用(2)的一个优点是,如果忘记了AsNoTracking(),那么结果应该是如此糟糕以至于很容易被注意到。
避免使用row_number()的任何变体,因为它通常会阻止在SQL引擎中有效使用谓词。 这可以通过使用谓词查看SQL实际计划来validation。 (道歉,因为这是我最初发布的建议。)
-- Avoid! select row_number() over (order by (select null)) as RowId, ...
希望EF团队考虑为视图提供一个选项,允许禁用Key要求并自动使用每个查询的AsNoTracking()。
在前两行的第6列,您具有相同的值 – 124,如果这是此视图中的某个外键,则可以导致一行被过滤。 我使用数据表Load函数有类似的情况,因为它在将检索到的数据加载到数据表时应用约束。 尝试从linq删除密钥到SQL模式。
实际上来自@stanke的问题给了我一个想法。
我实际上稍微改变了视图以包含另一列,以便可以唯一地标识每个记录。
我实际上并不需要在结果表中使用columns值,但它确实有助于LINQ在查询时保持记录的唯一性。 看来SQL本身就可以做到这一点,但LINQ需要一些帮助来保持记录的清晰。
它现在在SQL和LINQ中都能正常工作
我没有看到您的LINQ有任何问题。
你如何填充PartIndexes(ORM,SqlCommand等)?
也许你的DAL或ORM映射中的逻辑混乱了,这搞乱了PartIndexes中存储的内容。
假设您正在使用EF(entity framework) 。 如果是这样,请在IQueryable上使用.AsNoTracking() ,否则您可能会获得缓存结果。
我补充道
ISNULL(CONVERT(VARCHAR(50),NEWID()),”)AS Pkid
作为我在视图中的第一个专栏来解决这个问题。
上述就是C#学习教程:LINQ选择SQL视图得到错误的答案分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/960766.html