Tengo una lista de fechas como esta:
DateTime now = DateTime.Today; var expiriesDays = new List<int> { 1, 7, 14 }; List<DateTime> expiriesDates = expiriesDays.Select(x => now.AddDays(x).Date).ToList(); Ahora tengo una tabla y tiene un campo con el nombre ComplianceExpiryDate , ahora quiero verificar si este campo tiene algún valor de expiriesDates .
Como cualquier registro, tiene un valor como 13-07-2021 O 19-07-2021 O 26-07-2021 en ComplianceExpiryDate
Solo quiero comparar con la fecha, no con la hora.
Probé con TruncateTime pero, DbFunctions no muestra esta función para usar y arroja un error.
Esta es la solución sencilla que genera SQL con un IN .
También debe probar la solución de @GertArnold para ver qué se adapta mejor a su caso. La respuesta de @GertArnold está usando OR en lugar de IN , pero probablemente funcionará mejor cuando crezca su base de datos.
var today = DateTime.Today; // create a list of dates without time-part specified var expiryDays = new List<int> { 1, 7, 14 }; var expirationDates = expiryDays .Select(it => today.AddDays(it)) .ToList(); // insert test data into db var currentId = 1; foreach (var currentDate in expirationDates) { db.MyTables.Add(new MyTable { Id = currentId, ComplianceExpiryDate = currentDate.AddHours(3) // move time a few hours into the day }); currentId++; } db.SaveChanges(); var numberOfMatchingItems = db.MyTables .Count(e => expirationDates.Contains(e.ComplianceExpiryDate.Date)); Console.WriteLine( $"Number of matching dates found in db: {numberOfMatchingItems}");Producción:
Número de fechas coincidentes encontradas en db: 3
Usé esta definición para la clase de entidad con fecha:
public class MyTable { public int Id { get; set; } public DateTime ComplianceExpiryDate { get; set; } }SQL generado por EF:
SELECT COUNT(*) FROM "MyTables" AS "m" WHERE rtrim(rtrim(strftime('%Y-%m-%d %H:%M:%f', "m"."ComplianceExpiryDate", 'start of day'), '0'), '.') IN ('2021-07-14 00:00:00', '2021-07-20 00:00:00', '2021-07-27 00:00:00')Siempre debe tener cuidado al transformar los valores de la base de datos antes de filtrar. Porque eso es lo que sucederá al aplicar AddDays a ComplianceExpiryDate o al truncar su parte de tiempo y luego comparar los resultados con un valor de fecha dado. La base de datos tiene que transformar los valores de toda la tabla antes de compararlos. Eso puede ser costoso, pero es peor que cualquier índice en el campo de búsqueda ahora no se pueda usar. Este fenómeno se captura en una frase corta: no sargable .
Por lo tanto, siempre intente filtrar según los valores originales de la base de datos. Con las fechas, esto a menudo equivale a probar si una fecha se encuentra en algún intervalo de fechas. El enfoque aquí es crear un intervalo de un día para cada fecha de vencimiento.
En resumen, cree intervalos de fechas entre los que desea encontrar ComplianceExpiryDate y cree una consulta que tenga condiciones "entre la fecha de inicio y la fecha de finalización", combinadas con OR . Esto se hace mejor usando un generador de predicados, por ejemplo Linqkit, o este .
El código entonces se ve así:
DateTime now = DateTime.Today; var expiryDays = new List<int> { 1, 7, 14 }; var expirationIntervals = expiryDays .Select(x => (StartDate: now.AddDays(x - 1), EndDate: now.AddDays(x))).ToList(); Expression<Func<MyTable,bool>> predicate = PredicateBuilder.False<MyTable>(); predicate = expirationIntervals.Aggregate (predicate, (pred, tuple) => pred.Or(t => t.ComplianceExpiryDate >= tuple.StartDate && t.ComplianceExpiryDate < tuple.EndDate)); var result = MyTables.Where(predicate); Este método Or abreviado es un método de extensión en cualquiera de los constructores de predicados que encadena dos predicados en un predicado mediante un token "OrElse".