c语言编程笔录

首页 >   > 笔记大全

笔记大全

如何浅析Entity Framework Core2 0的日志记录与动态查询条件

更新时间:2023-11-25

浅析Entity Framework Core2 .0的日志记录与动态查询条件

Entity Framework Core2.0是.NET Core平台下面的一个ORM框架,在其2.0版本中,新增了对关系型数据库许多重要特性的支持,大大降低了开发者编写数据访问代码的难度,同时也提供了日志记录的功能,让我们在调试和排错的过程中能够更好的定位问题,并且还可以通过使用动态查询条件来简化查询构建过程。

一、EF Core 日志记录

EF Core提供了丰富的对运行时日志的支持,有助于我们找到程序中潜在的问题。在开发中,一种常见的日志记录方式是使用Console记录,比如下面的代码示例:

    using(var context = new MyDbContext())
    {
        context.Database.EnsureCreated();
  
        var blogs = context.Blogs.ToList();
        foreach (var blog in blogs)
        {
            Console.WriteLine(blog.Url);
        }
    }
  

在控制台上,我们就能看到EF运行时所产生的相关日志信息。除了使用Console记录日志以外,EF Core还支持将日志记录到文件中,我们可以在程序中指定记录日志的文件路径,比如下面的示例:

    using(var context = new MyDbContext())
    {
        var serviceProvider = context.GetInfrastructure();
        var loggerFactory = serviceProvider.GetService();
        loggerFactory.AddFile("log.txt");
  
        context.Database.EnsureCreated();
  
        var blogs = context.Blogs.ToList();
        foreach (var blog in blogs)
        {
            Console.WriteLine(blog.Url);
        }
    }
  

在这个示例中,我们通过使用ILoggerFactory来创建一个文件日志记录器的实例,指定了日志文件的路径。这样EF Core运行时的日志信息就会被记录到指定的文件中。

二、EF Core 动态查询条件

EF Core还提供了灵活的、基于Lambda表达式的动态查询条件,这使得我们在构建查询时可以避免编写大量重复的代码。查询条件的生成有多种方式,其中一个常用的方式就是使用一个QueryBuilder类,这个类提供了一组方法,使我们可以灵活地根据各种查询条件来构造查询表达式树。

    public class Filter
    {
        public string PropertyName { get; set; }
        public string Operation { get; set; }
        public object Value { get; set; }
    }
  
    public class Query
    {
        public List Filters { get; set; }
    }
  

上面这个示例定义了两个数据传输对象(DTO)Filter和Query。Filter代表一个查询条件的描述,包括属性名、操作符和比较值。Query包含多个Filter,代表一个完整的查询过程。下面是一个QueryBuilder类的示例,它接受Query对象作为参数,并生成一个Lambda表达式来查询符合条件的数据。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Reflection;
  
    namespace MyNamespace
    {
        public class QueryBuilder<T>
        {
            private IQueryable<T> _query;
            private static readonly MethodInfo ContainsMethod = typeof(string).GetMethod("Contains");
            private static readonly MethodInfo StartsWithMethod = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
            private static readonly MethodInfo EndsWithMethod = typeof(string).GetMethod("EndsWith", new[] { typeof(string) });
  
            public QueryBuilder(IQueryable<T> query)
            {
                _query = query;
            }
  
            public IQueryable<T> Build(Query query)
            {
                var lambda = CreateLambda(query);
                return _query.Where(lambda);
            }
  
            private Expression<Func<T, bool>> CreateLambda(Query query)
            {
                var param = Expression.Parameter(typeof(T), "x");
                Expression<bool> result = null;
  
                foreach (var filter in query.Filters)
                {
                    Expression left = Expression.Property(param, filter.PropertyName);
  
                    var right = Expression.Constant(filter.Value);
                    if (filter.Value != null && filter.Value.GetType() == typeof(string))
                    {
                        right = Expression.Constant(filter.Value.ToString().ToLower());
                    }
  
                    Expression comparison;
                    switch (filter.Operation)
                    {
                        case "eq":
                            comparison = Expression.Equal(left, right);
                            break;
                        case "ne":
                            comparison = Expression.NotEqual(left, right);
                            break;
                        case "ge":
                            comparison = Expression.GreaterThanOrEqual(left, right);
                            break;
                        case "gt":
                            comparison = Expression.GreaterThan(left, right);
                            break;
                        case "le":
                            comparison = Expression.LessThanOrEqual(left, right);
                            break;
                        case "lt":
                            comparison = Expression.LessThan(left, right);
                            break;
                        case "contains":
                            comparison = Expression.Call(left, ContainsMethod, right);
                            break;
                        case "startswith":
                            comparison = Expression.Call(left, StartsWithMethod, right);
                            break;
                        case "endswith":
                            comparison = Expression.Call(left, EndsWithMethod, right);
                            break;
                        default:
                            throw new NotSupportedException($"Filter operation '{filter.Operation}' not supported.");
                    }
  
                    if (result == null)
                    {
                        result = comparison;
                    }
                    else
                    {
                        result = Expression.AndAlso(result, comparison);
                    }
                }
  
                if (result == null)
                {
                    return null;
                }
                else
                {
                    return Expression.Lambda<Func<T, bool>>(result, param);
                }
            }
        }
    }
  

上面的代码中,QueryBuilder<T>是一个泛型类,它接受一个IQueryable<T>对象作为查询的初始表达式。Build方法接受一个Query对象,并以此来构建Lambda表达式树。CreateLambda方法是查询条件的核心方法,它根据Query.Filters中的查询条件来动态构建表达式树。最终结果是一个Lambda表达式,返回值为bool类型,实现了查询操作。

总结

在本篇文章中,我们浅析了Entity Framework Core2.0的日志记录与动态查询条件。在EF Core中,我们可以通过使用Console或文件来记录运行时日志,有助于我们查找程序中的潜在问题。同时,EF Core还提供了灵活的动态查询条件,使我们可以在构建查询时避免编写大量的重复代码,增强了开发效率。