EF Core 2.0 中的动态访问表

Posted

技术标签:

【中文标题】EF Core 2.0 中的动态访问表【英文标题】:Dynamically access table in EF Core 2.0 【发布时间】:2018-06-11 00:41:35 【问题描述】:

我正在使用System.Linq.Dynamic.Core 将 lambda 表达式动态添加到 EF 中的查询中。

我还希望能够按名称选择表。我找到了这个答案:

https://***.com/a/28101268/657477

但它不适用于 asp.net core 2.0。我不能使用DbSet 我必须使用DbSet<TEntity> 它在错误消息中说。

我希望能够做到db.GetTable("Namespace.MyTable").Where(...)

我该怎么做?

【问题讨论】:

TEntity 不是通用的吗? 看看这里***.com/a/44143131/2946329 【参考方案1】:

首先您需要从名称中获取实体的类型(如果您有类型,则直接使用它)。您可以为此使用反射,但 EF Core 的正确方法可能是使用 FindEntityType 方法。

一旦有了类型,问题就是如何获取对应的DbSet<T>。 EF Core 目前不提供类似于 EF6 的非泛型 Set(Type) 方法,主要是因为没有非泛型 DbSet 类。但是您仍然可以通过使用一些 EF Core 内部来获得对应的 DbSet<T>IQueryable

using System;
using System.Linq;
using Microsoft.EntityFrameworkCore.Internal;

namespace Microsoft.EntityFrameworkCore

    public static partial class CustomExtensions
    
        public static IQueryable Query(this DbContext context, string entityName) =>
            context.Query(context.Model.FindEntityType(entityName).ClrType);

        public static IQueryable Query(this DbContext context, Type entityType) =>
            (IQueryable)((IDbSetCache)context).GetOrAddSet(context.GetDependencies().SetSource, entityType);
    

或者(最好)通过反射调用通用的Set<T>方法:

using System;
using System.Linq;
using System.Reflection;

namespace Microsoft.EntityFrameworkCore

    public static partial class CustomExtensions
    
        public static IQueryable Query(this DbContext context, string entityName) =>
            context.Query(context.Model.FindEntityType(entityName).ClrType);

        static readonly MethodInfo SetMethod = typeof(DbContext).GetMethod(nameof(DbContext.Set), Type.EmptyTypes);

        public static IQueryable Query(this DbContext context, Type entityType) =>
            (IQueryable)SetMethod.MakeGenericMethod(entityType).Invoke(context, null);
    

在这两种情况下,您都可以使用如下内容:

db.Query("Namespace.MyTable").Where(...)

db.Query(typeof(MyTable)).Where(...)

【讨论】:

这很好用。感谢您帮助我,我真的很努力解决这个问题。 我遇到了这个方法的问题。我无法包含嵌套实体,因为 Include() 没有定义。有什么办法吗? 在我的情况下,IQueryable 不包含 Where 的定义 :( @mzain 它没有。所有 LINQ 扩展方法都是为 IQuerabley<T> 而不是为 IQueryable 定义的。因此,虽然答案显示了如何通过Type 检索DbSet,但返回的结果不能直接使用。如果事先知道T的类型,最好使用Set<T>()方法。 @Guerrilla 这个效果如何?如果没有通用类型,您将无法在 Iqueriable 上执行 .Where。【参考方案2】:

EF Core 不再有非通用的Set 方法,但是这个扩展类使得使用动态 linq 基于字符串查询表变得容易。将 TableTypeDictionary 视为 Dictionary<string, Type> 映射 DbSet 类型及其类型名称。

public static class DbContextExtensions

    public static IQueryable<Object> Set(this DbContext _context, Type t)
    
        return (IQueryable<Object>)_context.GetType().GetMethod("Set").MakeGenericMethod(t).Invoke(_context, null);
    


    public static IQueryable<Object> Set(this DbContext _context, String table)
    
        Type tableType;
        //One way to get the Type
        tableType = _context.GetType().Assembly.GetExportedTypes().FirstOrDefault(t => t.Name == table);
        //The Second way, get from the dictionary which we've initialized at startup
        tableType = TableTypeDictionary[table];
        //The third way, works only if 'table' is an 'assembly qualified type name'
        tableType = Type.GetType(table);

        IQueryable<Object> objectContext = _context.Set(tableType);
        return objectContext;
    

用法:

IQueryable<Object> query = db.Set("TableName");
//or if you're using the third way:
query = db.Set(MyTable.GetType().AssemblyQualifiedName);

// Filter against "query" variable below...
List<Object> result = query.ToList();
// or use further dynamic Linq
IQueryable<Object> query = db.Set("TableName").Where("t => t.TableFilter == \"MyFilter\"");

【讨论】:

TableTypeDictionary ? 方法 'Set' 没有重载需要 1 个参数 IQueryable&lt;Object&gt; 没有.Where(string) 的实现。 @HGMamaci 我已经编辑了答案以涵盖您的问题。 不再适用于 ef core6

以上是关于EF Core 2.0 中的动态访问表的主要内容,如果未能解决你的问题,请参考以下文章

Azure Functions .NET Core 中的 EF Core 2.0 连接字符串

如何从 .Net core 2.0 中的 HttpContext 获取访问令牌

基于ef core 2.0的数据库增删改审计系统

EF Core-2

EF Core 返回空关系,直到直接访问

EF Core 返回空关系,直到直接访问