Entity Frameworkのユーザー定義テーブルが不正なクエリを生成する


10

私は現在、Entity Framework 6とおそらくADO.NETのバグを経験していると思います。期限があるので、このバグが修正されるのを待つことができるかどうかわかりません。うまくいけば、誰かが私にクリーンな作業を手伝ってくれると思います。

問題は、クエリで値1と5が0.01と0.05になるはずの場所で使用されることです。しかし、奇妙なことに0.1は機能しているようです

生成されたクエリは現在次のとおりです(SQL Server Profilerから取得)

declare @p3  dbo.someUDT
insert into @p3 values(NULL,5)
insert into @p3 values(5,0.10)
insert into @p3 values(NULL,1)
insert into @p3 values(1,2)

exec sp_executesql N'Select * from @AName',N'@AName  [dbo].[someUDT] READONLY',@AName=@p3

正しいコードは次のとおりです。

declare @p3  dbo.someUDT
insert into @p3 values(NULL,0.05)
insert into @p3 values(0.05,0.10)
insert into @p3 values(NULL,0.01)
insert into @p3 values(0.01,0.02)

exec sp_executesql N'Select * from @AName',N'@AName  [dbo].[someUDT] READONLY',@AName=@p3

私はすでにgithubで問題を作成しました:ユーザー定義テーブルが間違った値を挿入

パラメーター化されたクエリでユーザー定義のテーブルを使用したいのですが、この質問では、これがどのように行われるかを説明します: エンティティフレームワークストアドプロシージャテーブルの値パラメーター

これは、上記のSQLコードを取得するために使用されるC#コードです

DataTable dataTable = new DataTable();
dataTable.Columns.Add("value1", typeof(decimal));
dataTable.Columns.Add("value2", typeof(decimal));

dataTable.Rows.Add(null,0.05m); 
dataTable.Rows.Add(0.05m,0.1m); 
dataTable.Rows.Add(null,0.01m); 
dataTable.Rows.Add(0.01m,0.02m); 
List<SqlParameter> Parameters = new List<SqlParameter>();

Parameters.Add(new SqlParameter("@AName", SqlDbType.Structured) { Value = dataTable , TypeName= "dbo.someUDT" });

dbContext.Database.ExecuteSqlCommand("Select * from @AName", Parameters.ToArray());

そして、ユーザー定義テーブルを取得するSQLコード

CREATE TYPE [dbo].[someUDT] AS TABLE
(
   [value1] [decimal](16, 5) NULL,
   [value2] [decimal](16, 5) NULL
)

編集:
ガートアーノルドはそれを理解しました。彼の回答に基づいて、既存のレポートをここで見つけましたSQL ServerプロファイラのTextData列が10進入力を誤って処理します


2
これを試してdataTable.Rows.Add(null,0.05m); 、それが生成するクエリを確認してください
rjs123431

1
@ rjs123431私は以前にそれを試しましたが、同じ結果が得られます
Joost K

1
新しいテーブルを作成して、テーブルのすべての値を返しますか?申し訳ありませんが、あなたが本当に望んでいることがわかりません。これであなたの主な目標は何ですか?
Lutti Coelho

1
@LuttiCoelhoは混乱を招き、申し訳ありませんSelect * from @ANameが、プレースホルダーです。私は実際には、質問に関連するとは思わなかったより大きなクエリでテーブルに参加しています。これは、問題をより簡単な形式で既に再現しているためです。
Joost K

2
奇妙なことに、確かに間違ったSQLが表示されますが、Database.SqlQuery(ではなくDatabase.ExecuteSqlCommand)を使用すると、クライアントで正しい値を受け取ります。
Gert Arnold

回答:


11

これは奇妙なSQLプロファイラーアーティファクトです。値は正しく転送されます。ユーザー定義型と1つの小さなテーブルを使用してデータベースを作成することで、そのことを示すことができます。

CREATE TABLE [dbo].[Values](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Value] [decimal](16, 5) NOT NULL,
 CONSTRAINT [PK_Values] PRIMARY KEY CLUSTERED ([Id] ASC) ON [PRIMARY]
GO

そして、いくつかの値を挿入します:

Id          Value
----------- ---------------------------------------
1           10.00000
2           1.00000
3           0.10000
4           0.01000

次に、少し調整したコードを実行します。

DataTable dataTable = new DataTable();
dataTable.Columns.Add("value1", typeof(decimal));
dataTable.Columns.Add("value2", typeof(decimal));

dataTable.Rows.Add(0.001m, 0.03m);
List<SqlParameter> Parameters = new List<SqlParameter>();

Parameters.Add(new SqlParameter("@AName", SqlDbType.Structured) { Value = dataTable, TypeName = "dbo.someUDT" });

using(var context = new MyContext(connStr))
{
    var query = "Select v.Id from dbo.[Values] v, @AName a "
        + " where v.Value BETWEEN a.value1 AND a.value2";
    var result = context.Database.SqlQuery<int>(query, Parameters.ToArray());
}

MyContex単なる継承クラスでDbContextあり、他には何もありません)

との間には値が1つだけ0.001mあり0.03m 、それがまさにクエリが返す値です4

ただし、SQL Serverプロファイラーはこれをログに記録します。

declare @p3 dbo.someUDT
insert into @p3 values(1,3) -- See here: the log is warped

exec sp_executesql N'Select v.Value from dbo.[Values] v, @AName a  where v.Value BETWEEN a.value1 AND a.value2',N'@AName [dbo].[someUDT] READONLY',@AName=@p3

そして、レコード#2を返すSSMSで。

それは地域設定と小数点区切り文字がロギングのどこかで小数点区切り文字と混同されていることに関係していると思います。


1
ロギングに問題があるとは思いもしませんでした。箱から出してすぐに考えて、これを解決してくれてありがとう!
Joost K

2
あなたの回答に基づいて、私はこのバグレポートを取得しましたfeedback.azure.com/forums/908035-sql-server/suggestions/…私だけではないようです。
Joost K

1

正直なところ、私はあなたと同じ問題はありません:

これは私のプロファイラログです。

declare @p3 dbo.someUDT
insert into @p3 values(NULL,0.05)
insert into @p3 values(0.05,0.10)
insert into @p3 values(NULL,0.01)
insert into @p3 values(0.01,0.02)

exec sp_executesql N'Select * from @AName',N'@AName [dbo].[someUDT] READONLY',@AName=@p3

EntityFrameworkバージョン6.2.0&6.3.0&6.4.0を試してみましたが、どれも問題を示していません。

DataTable dataTable = new DataTable();
dataTable.Columns.Add("value1", typeof(decimal));
dataTable.Columns.Add("value2", typeof(decimal));

dataTable.Rows.Add(null, 0.05);
dataTable.Rows.Add(0.05M, 0.1M);
dataTable.Rows.Add(null, 0.01);
dataTable.Rows.Add(0.01, 0.02);
List<SqlParameter> Parameters = new List<SqlParameter>();

Parameters.Add(new SqlParameter("@AName", SqlDbType.Structured) { Value = dataTable, TypeName = "dbo.someUDT" });

var dbContext = new test01Entities();
dbContext.Database.ExecuteSqlCommand("Select * from @AName", Parameters.ToArray());

また、私はADO.NETをテストして同じ結果を得ました。

SqlConnection cn = new SqlConnection("Data Source=(local);Initial Catalog=Test01;Integrated Security=true;");
using (var cmd = new SqlCommand("[foo]", cn))
{
    cmd.CommandType = CommandType.StoredProcedure;
    cn.Open();
    cmd.Parameters.AddWithValue("@param1", 0.02);
    cmd.Parameters.AddWithValue("@param2", 0.020);
    cmd.ExecuteNonQuery();
}

Visual Studio 2017、.NET Framework 4.6.1、Microsoft SQL Server Enterprise(64ビット)を使用しています


4
言語設定(マシンとデータベース)に関連していると確信しているので、あなたは幸運です。
Gert Arnold

2
私と@GertArnoldはどちらも同じ国に住んでいるため、両者が問題を再現できる理由を非常によく説明していることを付け加えておきます
Joost K

2
@GertArnoldサンプル(VS Solution + SQL Database)を作成して共有してください。手がかりを見つけます。
XAMT

1
@XAMTこれはSQL Server Profilerのバグなので、手に負えません。必要に応じて、マシンとデータベースサーバーの言語設定を操作して、コードの実行中にバグがいつ表示されるかを確認できますが、IMOは娯楽部門にあります。
Gert Arnold
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.