El miembro de tipo especificado 'Fecha' no es compatible con LINQ to Entities Exception

105

Obtuve una excepción al implementar las siguientes declaraciones.

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

Excepción

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

Sé lo que significa la excepción, pero no sé cómo deshacerme de ella. ¿Alguna ayuda?

nebulosa
fuente
Esto está en EF6 e inferior. Soportes principales de EF .Date.
Gert Arnold

Respuestas:

102

LINQ to Entities no puede traducir la mayoría de los métodos .NET Date (incluida la conversión que utilizó) a SQL, ya que no existe un SQL equivalente.

La solución es usar los métodos Date fuera de la declaración LINQ y luego pasar un valor. Parece que Convert.ToDateTime (rule.data) .Date está causando el error.

La llamada a la fecha en una propiedad DateTime tampoco se puede traducir a SQL, por lo que una solución alternativa es comparar las propiedades .Year .Month y .Day que se pueden traducir a LINQ ya que solo son números enteros.

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);
Judo
fuente
6
¿Qué pasa con j => j.JobDeadline.Date?
nebulosa
1
¿Date es una propiedad en JobDeadline? Esto no debería causar un error por sí solo, tal vez un conflicto de nombres (pero no estoy seguro de esto). Si la línea sigue causando un error, simplemente cámbiele el nombre DeadlineDate o similar.
Judo
1
La fecha es propiedad en JobDeadline. JobDeadline es el tipo DateTime del que quiero extraer Date.
nebulosa
Luego, para trabajar esto dentro de LINQ, necesitaría comparar la propiedad JobDeadline, por ejemplo, j.JobDeadline> ruleDate. Esto necesita un poco de prueba, pero se puede hacer que funcione. Alternativamente, compare las tres propiedades de .Month .Day y .Year (j.Deadline.Year == ruleDate.Year && j j.Deadline.Month == ruleDate.Month && j.Deadline.Day == ruleDate.Day). No es elegante, pero funciona, ya que solo son números enteros.
Judo
Hmm. Esta idea funciona. Sucio pero funciona. Si lo escribe como respuesta, puedo marcarlo como correcto.
nebulosa
230

Puede utilizar el método TruncateTime de EntityFunctions para lograr una traducción correcta de la Datepropiedad en 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);


Actualización: EntityFunctions está en desuso en EF6, useDbFunctions.TruncateTime

Slauma
fuente
Bueno, me di cuenta de que ruleDataes DateTimetipo y j.JobDeadlinetiene tiempo truncado. No se siente bien. No obtuve la excepción, pero tampoco obtuve el resultado esperado.
nebulosa
@aneal: Devuelve todos los registros donde JobDeadlinetiene la misma fecha que rule.data, sin importar la hora del día . ¿No es eso lo que quiere lograr con su consulta en la pregunta? ¿Por qué no se siente bien?
Slauma
1
+1 y estoy de acuerdo con lo anterior, definitivamente es una mejor respuesta para el 99% de las implementaciones
jim tollan
26
Tenga en cuenta que EntityFunctionsestá obsoleto en EF6, ahora debe usar DbFunctions.
Julien N
2
El espacio de nombres para DbFunctions en> EF6 es System.Data.Entity: msdn.microsoft.com/en-us/library/Dn220142(v=VS.113).aspx
GraehamF
39

Para EF6, utilice DbFunctions.TruncateTime (mydate) en su lugar.

KingOfHypocrites
fuente
9

"EntityFunctions.TruncateTime" o "DbFunctions.TruncateTime" en ef6 está funcionando pero tiene algún problema de rendimiento en Big Data.

Creo que la mejor manera es actuar así:

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

es mejor que usar partes de la fecha para. porque la consulta se ejecuta más rápido en datos grandes.

Mahdi Shahbazi
fuente
+1 para esta respuesta. EntityFunctions.TruncateTime(luego reemplazado por DbFunctions.TruncateTime) se implementan convirtiendo a SQL, donde la fecha y hora se convierte en una cadena y se trunca. Esto hace que la consulta se ejecute significativamente más lentamente, en proporción al número de registros procesados.
urig
3

Necesita incluir using System.Data.Entity;. Funciona bien incluso conProjectTo<>

var ruleDate = rule.data.Date;
return jobdescriptions.Where(j => DbFunctions.TruncateTime(j.Deadline) == ruleDate);
Omkar
fuente
Como ya se respondió aquí
Gert Arnold
1

Lo que significa es que LINQ to SQL no sabe cómo convertir la Datepropiedad en una expresión SQL. Esto se debe a que la Datepropiedad de la DateTimeestructura no tiene analogía en SQL.

Adam Robinson
fuente
1

Funcionó para mí.

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

Fuente: Foros de Asp.net

MRT2017
fuente
0

Tengo el mismo problema pero trabajo con DateTime-Ranges. Mi solución es manipular la hora de inicio (con cualquier fecha) a 00:00:00 y la hora de finalización a 23:59:59, por lo que ya no debo convertir mi DateTime a Date, sino que sigue siendo DateTime.

Si solo tiene una fecha y hora, también puede establecer la hora de inicio (con cualquier fecha) en 00:00:00 y la hora de finalización en 23:59:59. Luego, busque como si fuera un intervalo de tiempo.

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

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

También puede hacerlo 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);
peter70
fuente
0

puedes obtener Enum como:

DateTime todayDate = DateTime.Now.Date; var check = db.tableName.AsEnumerable().Select(x => new
        {
            Date = x.TodayDate.Date
        }).Where(x => x.Date == todayDate).FirstOrDefault();
Omid Soleiman
fuente
Esto es efectivamente enumerar todo el contenido de la tabla de antemano para aplicar el filtro de fecha ... ¡parece potencialmente una muy mala idea!
Javier Rapoport
0

Como muchos han señalado aquí, el uso de la función TruncateTime es lento.

Si puede, la opción más sencilla es utilizar EF Core. Puede hacer esto. Si no puede, una mejor alternativa para truncar es no cambiar el campo consultado en absoluto, sino modificar los límites. Si está haciendo una consulta normal de tipo 'entre' donde los límites inferior y superior son opcionales, lo siguiente será suficiente.

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

Básicamente, en lugar de recortar PoDate a solo la parte de Fecha, incrementamos el límite de consulta superior y el usuario <en lugar de <=

statler
fuente