Belirtilen tür üyesi 'Tarih' LINQ to Entities Exception'da desteklenmiyor


105

Aşağıdaki ifadeleri uygularken bir istisna yaşadım.

 DateTime result;
 if (!DateTime.TryParse(rule.data, out result))
     return jobdescriptions;
 if (result < new DateTime(1754, 1, 1)) // sql can't handle dates before 1-1-1753
     return jobdescriptions;
 return jobdescriptions.Where(j => j.JobDeadline.Date == Convert.ToDateTime(rule.data).Date );

İstisna

The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.

İstisnanın ne anlama geldiğini biliyorum ama ondan nasıl kurtulacağımı bilmiyorum. Herhangi bir yardım?


Bu EF6 ve daha düşük sürümdedir. EF çekirdek destekleri .Date.
Gert Arnold

Yanıtlar:


102

LINQ to Entities, eşdeğer bir SQL olmadığı için çoğu .NET Date yöntemini (kullandığınız çevrim dahil) SQL'e çeviremez.

Çözüm, LINQ ifadesinin dışında Date yöntemlerini kullanmak ve ardından bir değer iletmektir. Convert.ToDateTime (rule.data) .Date hataya neden oluyormuş gibi görünüyor.

DateTime özelliğindeki Date çağrısı da SQL'e çevrilemez, bu nedenle geçici bir çözüm, yalnızca tamsayı olduklarından LINQ'ya çevrilebilen .Year .Month ve .Day özelliklerini karşılaştırmaktır.

var ruleDate = Convert.ToDateTime(rule.data).Date;
return jobdescriptions.Where(j => j.Deadline.Year == ruleDate.Year 
                       && j.Deadline.Month == ruleDate.Month 
                       && j.Deadline.Day == ruleDate.Day);

6
Peki ya j => j.JobDeadline.Date?
nebula

1
Date JobDeadline'da bir özellik mi? Bu, kendi başına bir hataya neden olmamalıdır - belki bir adlandırma çatışması (ancak bundan emin değil). Satır hala bir hataya neden oluyorsa, sadece DeadlineDate veya benzeri bir adla yeniden adlandırın.
Judo

1
Date, JobDeadline'daki mülkiyettir. JobDeadline, DateTime'ı çıkarmak istediğim DateTime türüdür.
nebula

Daha sonra, bunu LINQ içinde çalıştırmak için sadece JobDeadline özelliğini, örneğin j.JobDeadline> ruleDate'i karşılaştırmanız gerekir. Bu biraz test gerektiriyor ancak işe yarayabilir. Alternatif olarak, .Month .Day ve .Year (j.Deadline.Year == ruleDate.Year && j j.Deadline.Month == ruleDate.Month && j.Deadline.Day == ruleDate.Day) üç özelliğini karşılaştırın. Zarif değil ama işe yarıyor çünkü bunlar sadece tamsayılar.
Judo

Hmm. Bu fikir işe yarıyor. Kirli ama işe yarıyor. Cevap olarak yazarsanız, doğru olarak işaretleyebilirim.
nebula

230

Özelliğin SQL'e doğru çevirilerini elde etmek için EntityFunctions'ın TruncateTime yöntemini kullanabilirsiniz :Date

using System.Data.Objects; // you need this namespace for EntityFunctions

// ...

DateTime ruleData = Convert.ToDateTime(rule.data).Date;
return jobdescriptions
    .Where(j => EntityFunctions.TruncateTime(j.JobDeadline) == ruleData);


Güncelleme: EntityFunctions EF6'da kullanımdan kaldırıldı, KullanımDbFunctions.TruncateTime


Bunun ruleDataçok DateTimetip olduğunu ve j.JobDeadlinezamanı kısalttığını fark ettim . Doğru gelmiyor. İstisna olmadı ama beklenen sonucu da alamadı.
nebula

@aneal: Tüm kayıtları döndüren JobDeadlineaynı sahiptir tarihi olarak rule.datane olursa olsun, günün saati . Sorudaki sorgunuzla elde etmek istediğiniz şey bu değil mi? Neden doğru hissettirmiyor?
Slauma

1
+1 ve yukarıdakilere katılıyorum, uygulamaların% 99'u için kesinlikle daha iyi bir cevap
jim tollan

26
Not EntityFunctionsEf6 önerilmiyor, artık kullanmalıdır DbFunctions.
Julien N

2
> EF6'daki DbFunctions için ad alanı System.Data.Entity: msdn.microsoft.com/en-us/library/Dn220142(v=VS.113).aspx
GraehamF


9

Ef6'daki "EntityFunctions.TruncateTime" veya "DbFunctions.TruncateTime" Çalışıyor ancak Büyük Veri'de bazı performans sorunları var.

Bence en iyi yol böyle davranmak:

DateTime ruleDate = Convert.ToDateTime(rule.data);

DateTime  startDate = SearchDate.Date;

DateTime  endDate = SearchDate.Date.AddDay(1);

return jobdescriptions.Where(j.Deadline >= startDate 
                       && j.Deadline < endDate );

tarihin bölümlerini kullanmaktan daha iyidir. çünkü büyük verilerde sorgu daha hızlı çalıştırılır.


Bu cevap için +1. EntityFunctions.TruncateTime(daha sonra ile değiştirilir DbFunctions.TruncateTime), tarih saatinin bir dizeye dönüştürüldüğü ve kesildiği SQL'e dönüştürülerek uygulanır. Bu, işlenen kayıtların sayısı ile orantılı olarak sorgunun önemli ölçüde daha yavaş çalışmasını sağlar.
urig

3

Eklenmesi gerekiyor using System.Data.Entity;. Şunlarla bile iyi çalışıyorProjectTo<>

var ruleDate = rule.data.Date;
return jobdescriptions.Where(j => DbFunctions.TruncateTime(j.Deadline) == ruleDate);

Daha önce cevaplandı burada
Gert Arnold

1

Bunun anlamı, LINQ to SQL'in Dateözelliği bir SQL ifadesine nasıl dönüştüreceğini bilmemesidir . Bunun nedeni, yapının Dateözelliğinin DateTimeSQL'de analogu olmamasıdır.


1

Benim için çalıştı.

DateTime dt = DateTime.Now.Date;
var ord = db.Orders.Where
      (p => p.UserID == User && p.ValidityExpiry <= dt);

Kaynak: Asp.net Forumları


0

Aynı sorunu yaşıyorum ama DateTime-Ranges ile çalışıyorum. Benim çözümüm, başlangıç ​​saatini (herhangi bir tarihle) 00:00:00 ve bitiş saatini 23:59:59 olarak değiştirmektir. Bu nedenle, DateTime'ı DateTime olarak değiştirmemeliyim, bunun yerine DateTime kalıyor.

Yalnızca bir Tarih Saatiniz varsa, başlangıç ​​saatini (herhangi bir tarihle) 00:00:00 ve bitiş saatini 23:59:59 olarak da ayarlayabilir ve ardından bir zaman aralığı gibi arama yapabilirsiniz.

var from = this.setStartTime(yourDateTime);
var to = this.setEndTime(yourDateTime);

yourFilter = yourFilter.And(f => f.YourDateTime.Value >= from && f.YourDateTime.Value <= to);

Bunu DateTime-Range ile de yapabilirsiniz:

var from = this.setStartTime(yourStartDateTime);
var to = this.setEndTime(yourEndDateTime);

yourFilter = yourFilter.And(f => f.YourDateTime.Value >= from && f.YourDateTime.Value <= to);

0

Enum'u şöyle alabilirsiniz:

DateTime todayDate = DateTime.Now.Date; var check = db.tableName.AsEnumerable().Select(x => new
        {
            Date = x.TodayDate.Date
        }).Where(x => x.Date == todayDate).FirstOrDefault();

Bu, tarih filtresini uygulamak için tablonun tüm içeriğini etkili bir şekilde numaralandırmaktır ... potansiyel olarak çok kötü bir fikir gibi görünüyor !
Javier Rapoport

0

Burada birçok kişi tarafından belirtildiği gibi, TruncateTime işlevini kullanmak yavaştır.

Yapabiliyorsanız en kolay seçenek EF Core kullanmaktır. Bunu yapabilir. Eğer yapamazsanız, kısaltmanın daha iyi bir alternatifi, sorgulanan alanı hiç değiştirmemek, ancak sınırları değiştirmektir. Alt ve üst sınırların isteğe bağlı olduğu normal bir 'arada' türü sorgu yapıyorsanız, aşağıdakiler hile yapacaktır.

    public Expression<Func<PurchaseOrder, bool>> GetDateFilter(DateTime? StartDate, DateTime? EndDate)
    {
        var dtMinDate = (StartDate ?? SqlDateTime.MinValue.Value).Date;
        var dtMaxDate = (EndDate == null || EndDate.Value == SqlDateTime.MaxValue.Value) ? SqlDateTime.MaxValue.Value : EndDate.Value.Date.AddDays(1);
        return x => x.PoDate != null && x.PoDate.Value >= dtMinDate && x.PoDate.Value < dtMaxDate;
    }

Temel olarak, PoDate'i yalnızca Tarih kısmına kırpmak yerine, üst sorgu sınırını ve <= yerine kullanıcı <değerini artırıyoruz.

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.