Entity Framework'te yanlış sorgu üreten kullanıcı tanımlı tablo


10

Şu anda Entity Framework 6 ve muhtemelen ADO.NET'te bir hata yaşıyorum düşünüyorum. Bir son tarih olduğundan, bu hatanın düzeltilmesini bekleyebileceğimden emin değilim ve umarım birisi bana temiz bir çalışma konusunda yardımcı olabilir.

Sorun, sorgu 0,01 ve 0,05 olması gereken yerlerde 1 ve 5 değerlerini kullanmasıdır. Ancak tuhaf bir şekilde 0.1 çalışıyor gibi görünüyor

Oluşturulan sorgu şu anda: (SQL Server Profiler'dan alınmıştır)

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

Doğru kod olsa da:

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

Zaten burada github üzerinde bir sorun oluşturdum: Kullanıcı tanımlı tablo yanlış değer ekleyerek

Parametreli sorgumda kullanıcı tanımlı bir tablo kullanmak istiyorum, bu soru bunun nasıl yapıldığını açıklar: Varlık Çerçevesi Saklı Yordam Tablo Değer Parametresi

Bu, yukarıdaki SQL kodunu almak için kullanılan C # kodudur

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

Ve kullanıcı tanımlı tablo almak için SQL kodu

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

EDIT:
Gert Arnold anladı. Onun cevabına dayanarak burada mevcut bir rapor buldum SQL Server Profiler TextData Sütunu Ondalık Girdileri Yanlış İşliyor


2
bunu deneyebilir dataTable.Rows.Add(null,0.05m); ve hangi sorguyu oluşturduğunu kontrol edebilir misiniz
rjs123431

1
@ rjs123431 Bunu daha önce denedim ve aynı sonucu veriyor
Joost K

1
Yeni bir tablo oluşturmak ve tablonun tüm değerlerini döndürmek mi istiyorsunuz? Üzgünüm, ama gerçekten ne istediğini anlamıyorum. Asıl amacın ne olduğunu bununla paylaşabilir misin?
Lutti Coelho

1
@LuttiCoelho karışıklık için özür dilerim, Select * from @ANameyer tutucu olarak. Aslında bu zaten sorunu daha basit bir biçimde çoğaltır beri soru ile ilgili olduğunu düşünmüyordu daha büyük bir sorguda masaya katılıyorum.
Joost K

2
Garip şey, gerçekten yanlış SQL görüyorum, ancak Database.SqlQuery(yerine Database.ExecuteSqlCommand) kullandığımda istemcide doğru değerleri alıyorum!
Gert Arnold

Yanıtlar:


11

Tuhaf bir Sql Profiler artefaktı. Değerler doğru şekilde aktarılır. Kullanıcı tanımlı türünüz ve bir küçük tablonuzla bir veritabanı oluşturarak bunu gösterebilirim:

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

Ve birkaç değer ekleyerek:

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

Sonra biraz adapte kodunuzu çalıştırın:

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

( MyContexsadece miras kalan bir sınıftır DbContextve başka bir şey değildir)

0.001mVe arasında sadece bir değer vardır0.03m o tam olarak ne sorgu döndürür var : 4.

Ancak, Sql Server profiler bunu günlüğe kaydeder:

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

Ve SSMS'de # 2 kaydı döndürür.

Ben bölgesel ayarları ve ondalık ayırıcılar günlük bir yerde ondalık grup ayırıcılar ile karıştırılması ile ilgili olduğunu düşünüyorum.


1
Günlüğe kaydedilen konuyla ilgili hiç düşünmemiştim. Kutunun dışında düşünmek harika ve bunu çözdüğünüz için teşekkür ederiz!
Joost K

2
Cevabınıza dayanarak bu hata raporunu aldım feedback.azure.com/forums/908035-sql-server/suggestions/… Görünüşe göre tek ben değildim.
Joost K

1

Dürüst olmak gerekirse, seninle aynı sorunum yok:

Bu benim Profiler Günlüğüm:

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 sürüm 6.2.0 & 6.3.0 & 6.4.0'ı denedim ve bunların hiçbiri sorunu göstermiyor:

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

Ayrıca, ADO.NET test ve aynı sonucu var:

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 ve Microsoft SQL Server Enterprise (64 bit) kullanıyorum


4
Dil ayarları (makine vs veritabanı) ile ilgili olduğundan eminim, bu yüzden sadece şanslısınız.
Gert Arnold

2
Ben ve @GertArnold her ikisinin de aynı ülkede yaşadığını eklemeliyim ki, neden ikisini de sorunu yeniden oluşturabileceğimize dair çok olası bir açıklama var
Joost K

2
@GertArnold Lütfen bir örnek yapın (VS Solution + SQL Database) ve paylaşın. Ben ipucunu bulacağım.
XAMT

1
@XAMT Bu bir Sql Server Profiler hatası, bu yüzden ellerimizin dışında. İsterseniz, kodunuzu çalıştırırken hatanın ne zaman göründüğünü görmek için makinenizin ve veritabanı sunucunuzun dil ayarları ile oynayabilirsiniz, ancak IMO, eğlence departmanındadır.
Gert Arnold
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.