9

8列の応答を生成するSQLビューがあります。かなり複雑なので、ここではリストしません。また、理解しようとしている問題にあまり追加しません。

このクエリを使用してSQLManagerでビューを直接クエリすると

SELECT * FROM [GPPS].[dbo].[PartIndex]
WHERE CategoryNameId = 182 AND CycleId = 13 AND BasketId = 304 AND MarketId = 8
ORDER BY ProductNameId

(最初の2行が重要です)の期待される結果が得られ、ProductNameId列は結果の7番目です

                            vvvvv
                            =====   
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);

私が実際に得るのは:

                            vvvvv
                            ===== 
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

ご覧のとおり、最初の2つのエントリは同一であり、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リクエストを実行するとSQLとは異なる結果が返されるのか、LINQクエリによって生成されたSQLを実行すると、目的の結果が返されるのかがわかりました。

正しく表示するときにLINQが実行しない、直接使用する場合のSQLは何を実行しますか?

4

7 に答える 7

8

あなたの問題はこれに似ています:エンティティで主キーのないビューを使用する

行を一意にするキーを指定します。属性を介して、エンティティマッピングでこれらのキーを指定できます。

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<YearlySalesOnEachCountry>()
           .HasKey(x => new { x.CountryId, x.OrYear });     
}
于 2013-01-08T15:34:17.377 に答える
5

エンティティフレームワークがビューに対して選択するキーが一意でない場合、結果が正しく返されない可能性があります。一部のビューでは、適切なキー(null以外のすべての列を含む)を定義できず、ビューを使用するメリットがありません。

このような場合は、EFEdmxインターフェイスを使用してキーを手動で次のように定義することを検討してください。

 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()を忘れた場合、結果が非​​常に悪くなり、簡単に気付くことができることです。

SQLエンジン内での述語の効率的な使用を妨げることが多いため、row_number()のバリアントの使用は避けてください。これは、述語を使用してSQL実績計画を表示することで確認できます。(私が最初に投稿したアドバイスだったので、お詫びします。)

   -- Avoid!
   select row_number() over (order by (select null)) as RowId,
          ...

うまくいけば、EFチームは、キー要件の無効化と各クエリでのAsNoTracking()の自動使用を可能にするビューのオプションを検討するでしょう。

于 2015-04-02T23:37:51.663 に答える
2

実際、@stankeからの質問は私にアイデアを与えました。

実際には、各レコードを一意に識別できるように、ビューを少し変更して別の列を含めました。

結果のテーブルに列の値は実際には必要ありませんが、クエリ時にLINQがレコードを一意に保つのに役立ちました。SQLはそれ自体でこれをうまく実行しているように見えますが、LINQは、レコードを区別するために少しの支援が必要でした。

SQLとLINQの両方で期待どおりに機能するようになりました

于 2013-01-08T15:19:34.693 に答える
2

追加した

ISNULL(CONVERT(VARCHAR(50), NEWID()), '') AS Pkid 

この問題に対処するための私の見解の最初の列として。

于 2017-08-08T18:32:17.097 に答える
1

最初の2行の6番目の列には、同じ値(124)があります。これは、このビューの外部キーである場合、1つの行がフィルタリングされる可能性があります。取得したデータをデータテーブルにロードするときに制約を適用するため、データテーブルのロード関数を使用しても同様の状況が発生しました。linqからsqlスキーマへのキーを削除してみてください。

于 2013-01-08T14:52:45.567 に答える
0

LINQに問題はありません。

PartIndexes(ORM、SqlCommandなど)をどのように設定していますか?

おそらく、DALまたはORMマッピングのロジックが台無しになっていて、PartIndexesに格納されているものが台無しになっています。

于 2013-01-08T14:56:59.793 に答える
0

EF(エンティティフレームワーク)を使用していると仮定します。その場合は、IQueryableで.AsNoTracking()を使用してください。そうしないと、結果がキャッシュされる可能性があります。

于 2015-02-06T15:58:21.997 に答える