Bảng do người dùng xác định trong Entity Framework tạo truy vấn không chính xác


10

Tôi nghĩ rằng tôi hiện đang gặp một lỗi trong Entity Framework 6 và có thể là ADO.NET. Vì có thời hạn, tôi không chắc mình có thể đợi lỗi này được sửa và hy vọng ai đó có thể giúp tôi làm việc sạch sẽ.

Vấn đề là truy vấn sử dụng các giá trị 1 và 5 ở những nơi cần là 0,01 và 0,05. Tuy nhiên, thật kỳ lạ, 0,1 dường như đang hoạt động

Truy vấn được tạo hiện tại là: (nhận được từ 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

Trong khi mã chính xác sẽ là:

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

Tôi đã tạo một vấn đề trên github ở đây: Bảng do người dùng xác định chèn giá trị sai

Tôi muốn sử dụng bảng do người dùng xác định trong truy vấn được tham số hóa của mình, câu hỏi này giải thích cách thực hiện: Entity Framework Lưu trữ thủ tục Bảng tham số giá trị

Đây là mã C # được sử dụng để lấy mã SQL ở trên

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());

Và mã SQL để có được bảng do người dùng định nghĩa

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

EDIT:
Gert Arnold đã tìm ra nó. Dựa trên câu trả lời của anh ấy, tôi đã tìm thấy một báo cáo hiện có ở đây SQL Server Profiler TextData Cột xử lý các đầu vào thập phân không chính xác


2
bạn có thể thử cái này không dataTable.Rows.Add(null,0.05m); và kiểm tra xem nó tạo ra truy vấn nào
rjs123431

1
@ rjs123431 Tôi đã thử điều đó trước đây và nó cho kết quả tương tự
Joost K

1
Bạn muốn tạo một bảng mới và trả về tất cả các giá trị của bảng? Xin lỗi, nhưng tôi không hiểu bạn thực sự muốn gì. Bạn có thể chia sẻ mục tiêu chính của bạn với điều này là gì?
Lutti Coelho

1
@LuttiCoelho xin lỗi vì sự nhầm lẫn, Select * from @ANamelà như giữ chỗ. Tôi thực sự đang tham gia trên bàn trong một truy vấn lớn hơn mà tôi không nghĩ là có liên quan đến câu hỏi vì điều này đã sao chép vấn đề ở định dạng đơn giản hơn.
Joost K

2
Điều kỳ lạ là, tôi thực sự thấy SQL không chính xác, nhưng khi tôi sử dụng Database.SqlQuery(chứ không phải Database.ExecuteSqlCommand) tôi nhận được các giá trị chính xác trong máy khách!
Gert Arnold

Câu trả lời:


11

Đó là một tạo phẩm Sql Profiler kỳ lạ. Các giá trị được chuyển chính xác. Tôi có thể chứng minh rằng bằng cách tạo cơ sở dữ liệu với loại do người dùng xác định và một bảng nhỏ:

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

Và chèn một vài giá trị:

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

Sau đó, tôi chạy mã của bạn, hơi thích nghi:

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());
}

( MyContexchỉ là một lớp kế thừa từ DbContextvà không có gì khác)

Chỉ có một giá trị giữa 0.001m0.03m và đó là chính xác những gì các truy vấn trả về : 4.

Tuy nhiên, Sql Server profiler ghi lại điều này:

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

Và trong SSMS trả về bản ghi # 2.

Tôi nghĩ rằng nó phải được thực hiện với các cài đặt khu vực và dấu tách thập phân được trộn lẫn với dấu tách nhóm thập phân ở đâu đó trong nhật ký.


1
Tôi không bao giờ nghĩ về vấn đề đang đăng nhập. Tuyệt vời ra khỏi hộp suy nghĩ và cảm ơn bạn đã giải quyết điều này!
Joost K

2
Dựa trên câu trả lời của bạn, tôi đã nhận được báo cáo lỗi này feedback.azure.com/forums/908035-sql-server/suggestions/ gợi Có vẻ như tôi không phải là người duy nhất.
Joost K

1

Thành thật mà nói, tôi không có vấn đề giống như bạn:

Đây là Nhật ký hồ sơ của tôi:

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

Tôi đã thử EntityFramework phiên bản 6.2.0 & 6.3.0 & 6.4.0 và không có cái nào trong số này cho thấy vấn đề:

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());

Ngoài ra, tôi kiểm tra ADO.NET và có kết quả tương tự:

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();
}

Tôi đang sử dụng Visual Studio 2017, .NET Framework 4.6.1 và Microsoft SQL Server Enterprise (64-bit)


4
Tôi khá chắc chắn rằng nó liên quan đến cài đặt ngôn ngữ (máy so với cơ sở dữ liệu), vì vậy bạn thật may mắn.
Gert Arnold

2
Tôi phải nói thêm rằng tôi và @GertArnold đều sống ở cùng một quốc gia, điều đó giải thích rất có thể tại sao chúng ta có thể tái tạo vấn đề
Joost K

2
@GertArnold Vui lòng tạo một mẫu (VS Solution + Cơ sở dữ liệu SQL) và chia sẻ nó. Tôi sẽ tìm ra manh mối.
XAMT

1
@XAMT Đó là một lỗi Trình biên dịch máy chủ Sql vì vậy nó nằm ngoài tầm tay của chúng tôi. Nếu bạn thích, bạn có thể chơi với các cài đặt ngôn ngữ của máy chủ và cơ sở dữ liệu để xem khi nào lỗi xuất hiện trong khi bạn chạy mã của mình, nhưng IMO đó là trong bộ phận tiêu khiển.
Gert Arnold
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.