c# - 在 DbContext 中动态查找通用 DbSet

标签 c# .net asp.net-mvc-5 entity-framework-core

我知道这个问题已经有人问过,但我找不到令我满意的答案。我想做的是检索一个特定的 DbSet<T>基于其类型的名称。

我有以下内容:

[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("MyDllAssemblyName")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("MyCallingAssemblyName")]

class MyDbContext : DbContext {

    public DbSet<ModelA> A { get; set; }
    public DbSet<ModelB> B { get; set; }

    public dynamic GetByName_SwitchTest(string name) {
        switch (name) {
            case "A": return A;
            case "B": return B;
        }
    }

    public dynamic GetByName_ReflectionTest(string fullname)
    {
        Type targetType = Type.GetType(fullname);
        var model = GetType()
            .GetRuntimeProperties()
            .Where(o => 
                o.PropertyType.IsGenericType &&
                o.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>) &&
                o.PropertyType.GenericTypeArguments.Contains(targetType))
            .FirstOrDefault();
        if (null != model)
            return model.GetValue(this);
        return null;
    }
}

无论是通过简单的开关还是反射,我都可以轻松获取类型本身。但是我需要将类型作为动态返回,因为我不知道它将是什么 DbSet 类型。 然后在同一个程序集中的其他地方,我这样使用它:

// MyDbContext MyDbContextInstance..
var model = MyDbContextInstance.GetByName_SwitchTest("A");
var record1 = model.FirstOrDefault(); // It crashes here with RunTimeBinderException

此时model包含一个 InternalDbSet<ModelA> 的实例类型。从那里开始,我对 model 所做的任何使用对象我得到一个 RunTimeBinderException : “Microsoft.Data.Entity.Internal.InternalDbSet”不包含“FirstOrDefault”的定义

在网上调查,我发现了一个 blog post解释说(引用他的博客):

the reason the call to FirstOrDefault() fails is that the type information of model is not available at runtime. The reason it's not available is because anonymous types are not public. When the method is returning an instance of that anonymous type, it's returning a System.Object which references an instance of an anonymous type - a type whose info isn't available to the main program.

然后他指出了一个解决方案:

The solution is actually quite simple. All we have to do is open up AssemplyInfo.cs of the ClassLibrary1 project and add the following line to it: [assembly:InternalsVisibleTo("assembly-name")]

我确实在我的代码上尝试过这个解决方案,但它不起作用。有关信息,我有一个 asp.net 5 解决方案,其中有两个程序集在 dnx dotnet46 上运行。一个应用程序和一个包含我所有模型和 DbContext 的 dll。不过,我所做的所有相关调用都位于 dll 中。

这个解决方案有机会奏效吗? 我错过了什么吗? 任何指针将不胜感激?

提前致谢

[编辑]

我已经尝试返回 IQueryable<dynamic>而不是 dynamic我可以做基本查询 model.FirstOrDefault(); 最重要的是,我也希望能够在字段上进行过滤:

var record = model.FirstOrDefault(item => item.MyProperty == true);

最佳答案

那么当我不知道 <T> 时,我是怎么做到的?在编译期间。

首先需要获取类型,因为 DbContext.Set 方法返回一个非通用 DbSet 实例,用于访问上下文和底层存储中给定类型的实体。

public virtual DbSet Set(Type entityType)

注意这里的参数是应该返回集合的实体类型。给定实体类型的集合是返回值。

var type = Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(t => t.Name == <Pass your table name>);

现在一旦我有了这个类型

if(type != null)
{
DbSet context = context.Set(type);
}

或者一个类轮会是

DbSet mySet = context.Set(Type.GetType("<Your Entity Name>"));

关于c# - 在 DbContext 中动态查找通用 DbSet,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33940507/

相关文章:

c# - process.MainWindowHandle 为零?

c# - EF4.0 中的延迟加载正在卡住 UI

c# - LinQ to SQL 忽略 != 虚拟属性上的 null

c# - UserManager.SendEmailAsync 挂起

c# - 使用多个主机设置 CORS 配置

c# - 在更改密码页面上重定向用户和 "block"他

c# - Unity 中的按钮,不使用 UI?

C# Entity Framework 属性(有时)为空

.net - Wf 4 接收事件 : Difference between Messages and Parameters

c# - 如何使用 c# 从 asp.net 中的查询字符串中删除项目?