私は現在、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で問題を作成しました: 間違った値を挿入するユーザー定義テーブル
パラメーター化されたクエリでユーザー定義テーブルを使用したいのですが、この質問では、これがどのように行われるかを説明します: Entity Frameworkストアドプロシージャテーブルの値パラメーター
これは、上記の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
)
編集:
Gert Arnold 考え出した。彼の回答に基づいて、ここに既存のレポートを見つけました SQL Server Profiler TextData列が10進数入力を正しく処理しません
これは奇妙な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
を継承したクラスであり、それ以外のものはありません)
0.001m
と0.03m
の間の値は1つだけですそして、クエリが返すのはまさにこれです: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で。
それは地域設定と小数点区切り文字がロギングのどこかで小数点区切り文字と混同されていることに関係していると思います。
正直なところ、私はあなたと同じ問題を抱えていません:
これは私のプロファイラログです。
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ビット)を使用しています