Il membro del tipo specificato "Date" non è supportato in LINQ to Entities Exception


105

Ho ricevuto un'eccezione durante l'implementazione delle seguenti dichiarazioni.

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

Eccezione

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

So cosa significa l'eccezione ma non so come liberarmene. Qualsiasi aiuto?


Questo è in EF6 e inferiore. Supporta EF core .Date.
Gert Arnold

Risposte:


102

LINQ to Entities non può tradurre la maggior parte dei metodi .NET Date (incluso il casting utilizzato) in SQL poiché non esiste un SQL equivalente.

La soluzione consiste nell'usare i metodi Date all'esterno dell'istruzione LINQ e quindi passare un valore. Sembra che Convert.ToDateTime (rule.data) .Date stia causando l'errore.

Anche la chiamata di Date su una proprietà DateTime non può essere tradotta in SQL, quindi una soluzione alternativa è confrontare le proprietà .Year .Month e .Day che possono essere tradotte in LINQ poiché sono solo numeri interi.

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
Che mi dici di j => j.JobDeadline.Date?
nebulosa

1
Date è una proprietà su JobDeadline? Questo non dovrebbe causare un errore di per sé, forse un conflitto di denominazione (ma non è sicuro su questo). Se la linea continua a causare un errore, rinominala DeadlineDate o simile.
Judo

1
La data è proprietà su JobDeadline. JobDeadline è il tipo DateTime di cui desidero estrarre Date.
nebulosa

Quindi, per funzionare in LINQ è necessario confrontare semplicemente la proprietà JobDeadline, ad esempio j.JobDeadline> ruleDate. Questo richiede un po 'di test ma può essere fatto funzionare. In alternativa, confronta le tre proprietà di .Month .Day e .Year (j.Deadline.Year == ruleDate.Year && j j.Deadline.Month == ruleDate.Month && j.Deadline.Day == ruleDate.Day). Non è elegante ma funziona poiché questi sono solo numeri interi.
Judo

Hmm. Questa idea funziona. Sporco ma funziona. Se lo scrivi come risposta posso contrassegnarlo come corretto.
nebulosa

230

È possibile utilizzare il TruncateTime il metodo delle EntityFunctions per ottenere una corretta traduzione della Dateproprietà in SQL:

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


Aggiornamento: EntityFunctions è deprecato in EF6, UsaDbFunctions.TruncateTime


Bene, ho notato che ruleDataè di DateTimetipo e j.JobDeadlineha un tempo troncato. Non mi sembra giusto. Non ho ricevuto eccezioni ma non ho ottenuto neanche il risultato atteso.
nebulosa

@aneal: Esso restituisce tutti i record in cui JobDeadlineha la stessa data di come rule.data, non importa qual è il momento della giornata . Non è quello che vuoi ottenere con la tua query nella domanda? Perché non sembra giusto?
Slauma

1
+1 e sono d'accordo con quanto sopra, è sicuramente una risposta migliore per il 99% delle implementazioni
jim tollan

26
Nota che EntityFunctionsè deprecato in EF6, ora dovresti usare DbFunctions.
Julien N

2
Namespace per DbFunctions a> EF6 è System.Data.Entity: msdn.microsoft.com/en-us/library/Dn220142(v=VS.113).aspx
GraehamF


9

"EntityFunctions.TruncateTime" o "DbFunctions.TruncateTime" in ef6 funziona ma ha qualche problema di prestazioni in Big Data.

Penso che il modo migliore sia agire in questo modo:

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

è meglio che usare parti della data fino a. perché la query viene eseguita più velocemente con dati di grandi dimensioni.


+1 per questa risposta. EntityFunctions.TruncateTime(successivamente sostituiti da DbFunctions.TruncateTime) vengono implementati convertendo in SQL dove il datetime viene convertito in una stringa e che viene troncato. Ciò rende l'esecuzione della query notevolmente più lenta, in proporzione al numero di record elaborati.
urig

3

È necessario includere using System.Data.Entity;. Funziona bene anche conProjectTo<>

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

Come è stato già risposto qui
Gert Arnold

1

Ciò significa che LINQ to SQL non sa come trasformare la Dateproprietà in un'espressione SQL. Questo perché la Dateproprietà della DateTimestruttura non ha analoghi in SQL.


1

Ha funzionato per me.

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

Fonte: forum Asp.net


0

Ho lo stesso problema ma lavoro con DateTime-Ranges. La mia soluzione è manipolare l'ora di inizio (con qualsiasi data) a 00:00:00 e l'ora di fine a 23:59:59 Quindi non devo più convertire il mio DateTime in Date, piuttosto rimane DateTime.

Se hai un solo DateTime, puoi anche impostare l'ora di inizio (con qualsiasi data) a 00:00:00 e l'ora di fine a 23:59:59 Quindi cerchi come se fosse un intervallo di tempo.

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

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

Puoi farlo anche con DateTime-Range:

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

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

0

puoi ottenere Enum come:

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

Questo è effettivamente enumerare l'intero contenuto del tavolo in anticipo, al fine di applicare il filtro data ... sembra potenzialmente un molto cattiva idea!
Javier Rapoport

0

Come è stato sottolineato da molti qui, l'utilizzo della funzione TruncateTime è lento.

L'opzione più semplice se possibile è usare EF Core. Può farlo. Se non puoi, un'alternativa migliore al troncamento è non modificare affatto il campo richiesto, ma modificare i limiti. Se stai eseguendo una normale query di tipo "tra" in cui i limiti inferiore e superiore sono opzionali, quanto segue farà il trucco.

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

Fondamentalmente, invece di ridurre PoDate solo alla parte della data, incrementiamo il limite superiore della query e l'utente <invece di <=

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.