Recherche d'un DateTime à l'aide d'une string de search dans le code Entity Framework en premier

J'ai un projet MVC qui génère un DateTime ( DateTime? ) Nullable comme une string à l'user pour chaque élément de model comme indiqué ci-dessous (mon interface user a pagination donc je fais seulement ce calcul pour un petit nombre d'loggings – en d'autres termes, cette partie est d'accord):

 foreach (DocumentEvent item in Model.items) @(item?.TimeUtc?.ToSsortingng() ?? "N/A") 

Je veux append une fonctionnalité de search. J'ai essayé de chercher comme suit, mais ce n'est pas performant car AsEnumerable matérialise ma list et je suis maintenant dans le monde C #, en énumérant chaque logging:

 using (var context = new ClientEventsContext()) var items = context.Events.AsEnumerable().Where(x => { (x?.TimeUtc?.ToSsortingng() ?? "N/A").Contains(model.search) }); 

Au lieu de cela, je veux tirer parti de ma database SQL Server. Comment puis-je créer une requête SQL Server-friendly pour le code ci-dessus sans AsEnumerable qui produira les mêmes résultats que ma logique actuelle?

Voici comment vous pouvez générer et utiliser la conversion compatible LINQ to Entities de date en string au format M/d/yyyy h:mm:ss tt . Plutôt que d'intégrer ce monstre dans la requête, j'utiliserai une méthode "marker" personnalisée et lierai l'implémentation en utilisant ExpressionVisitor . De cette façon, vous pouvez expérimenter et modifier le format si nécessaire (même append quelques arguments de contrôle) sans affecter la lisibilité de la requête.

Premièrement, la mise en œuvre:

 public static class EFExtensions { public static ssortingng ToCustomDateFormat(this DateTime value) { // Should never happen throw new InvalidOperationException(); } public static IQueryable<T> ApplyCustomDateFormat<T>(this IQueryable<T> source) { var expression = new CustomDateFormatBinder().Visit(source.Expression); if (source.Expression == expression) return source; return source.Provider.CreateQuery<T>(expression); } class CustomDateFormatBinder : ExpressionVisitor { protected override Expression VisitMethodCall(MethodCallExpression node) { if (node.Method.DeclaringType == typeof(EFExtensions) && node.Method.Name == "ToCustomDateFormat") { var date = Visit(node.Arguments[0]); var year = DatePart(date, v => DbFunctions.Right("0000" + v.Year, 4)); var month = DatePart(date, v => v.Month.ToSsortingng()); var day = DatePart(date, v => v.Day.ToSsortingng()); var hour = DatePart(date, v => (1 + (v.Hour + 11) % 12).ToSsortingng()); var minute = DatePart(date, v => DbFunctions.Right("0" + v.Minute, 2)); var second = DatePart(date, v => DbFunctions.Right("0" + v.Second, 2)); var amPM = DatePart(date, v => v.Hour < 12 ? "AM" : "PM"); var dateSeparator = Expression.Constant("/"); var timeSeparator = Expression.Constant(":"); var space = Expression.Constant(" "); var result = Expression.Call( typeof(ssortingng).GetMethod("Concat", new Type[] { typeof(ssortingng[]) }), Expression.NewArrayInit(typeof(ssortingng), month, dateSeparator, day, dateSeparator, year, space, hour, timeSeparator, minute, timeSeparator, second, space, amPM)); return result; } return base.VisitMethodCall(node); } Expression DatePart(Expression date, Expression<Func<DateTime, ssortingng>> part) { var parameter = part.Parameters[0]; parameterMap.Add(parameter, date); var body = Visit(part.Body); parameterMap.Remove(parameter); return body; } Dictionary<ParameterExpression, Expression> parameterMap = new Dictionary<ParameterExpression, Expression>(); protected override Expression VisitParameter(ParameterExpression node) { Expression replacement; return parameterMap.TryGetValue(node, out replacement) ? replacement : node; } } } 

puis l'utilisation:

 var items = context.Events .Where(x => x.TimeUtc != null && x.TimeUtc.Value.ToCustomDateFormat().Contains(model.search)) .ApplyCustomDateFormat(); 

J'ai trouvé une solution. Cette syntaxe semble fonctionner:

 using (var context = new ClientEventsContext()) var items = context.Events.Where(x => { x.TimeUtc.HasValue && x.TimeUtc.Value.ToSsortingng().Contains(model.search) }); 

Une autre solution utilisant la bibliothèque SqlFunctions pour convertir n'importe quoi à Raw Query et faire le travail au niveau SQL, par exemple:

 using (var context = new ClientEventsContext()) var items = context.Events.Where(x => SqlFunctions.PatIndex(model.search, SqlFunctions.DateName('your pattern here', x?.TimeUtc) ?? "N/A").Value > -1 );