如何在Entity Framework Core的DbContext中设置动态实体?

8

我有一个方法,接收一个实体字符串并返回该实体的列表。

我想要的是动态设置实体并返回结果。

我需要的是像这样的东西:

DbContext.Set <Type.GetType("Entity")>().Select(e => e);

我遇到的错误是:

错误

也许这不是正确的处理方式。

Set 方法来自 Entity Framework Core。

Set 方法


2
问题在于我认为 EntityFrameworkCore 不支持。 - Rabel Obispo
2
抱歉!但Set方法来自于EntityFrameworkCore - Rabel Obispo
以下内容与此相反 https://msdn.microsoft.com/zh-cn/library/gg679544(v=vs.103).aspx - SILENT
2
我看到问题了,很抱歉,问题在于我正在使用的是 EntityFrameworkCore 而不是 EntityFramework 5 或 6,这些是其他版本。 - Rabel Obispo
1
我刚试过这个方法,https://dev59.com/jFYN5IYBdhLWcg3wEEYm - fuzzybear
显示剩余6条评论
3个回答

1

首先,这只是一个示例,而不是针对您特定问题的解决方案。

我的实体类

using System;
using System.Collections.Generic;
using System.Text;

namespace MyIdentityModel
{
    public class IdentityRole
    {
        public long Id { get; set; } 
        public string Name { get; set; } = null!;
        public DateTimeOffset CreatedAt { get; set; }
        public bool Active { get; set; }
        public bool Enabled { get; set; }
        public DateTimeOffset ActiveUntil { get; set; }

    }
}

我的语境

using MyIdentityModel.Configuration;
using Microsoft.EntityFrameworkCore;
using System;

namespace MyIdentityModel
{

    public abstract class IdentityDbContextBase: DbContext
    {

        public IdentityDbContextBase(DbContextOptions options) : base(options)
        {
        }

        
        public DbSet<IdentityRole> Roles { get; set; } = null!;
        

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
                        modelBuilder.ApplyConfiguration(new IdentityRoleConfiguration());
           
        }
    }
}

示例解决方案
我有三种方法

public List<TResult> GetList<TResult>(DbContext context, string entityTypeName)
    where TResult : class
{
    Type entityType = Type.GetType(entityTypeName); // get type of entity / MyIdentityModel.IdentityRole
    var setMethod = context.GetType().GetMethod(nameof(DbContext.Set), new Type[] { }).MakeGenericMethod(entityType); //Get Method Set<MyIdentityModel.IdentityRole>
    var dbSet = setMethod.Invoke(context, new object[] { }); // Calling context.Set<MyIdentityModel.IdentityRole>
    /* Call to another methods using reflection before calling "ToList" 
        Eg. example Where, Include, Select
        */
    var toListMethod = typeof(Enumerable).GetMethod("ToList").MakeGenericMethod(entityType); //get Extension Method "ToList<MyIdentityModel.IdentityRole>"
    var list = (List<TResult>)toListMethod.Invoke(null, new object[] { dbSet });//Calling "context.Set<MyIdentityModel.IdentityRole>.ToList<MyIdentityModel.IdentityRole>()" Method and convert to destination type if is possible.
    return list;
}

public List<TEntity> GetList2<TEntity>(DbContext context)
    where TEntity : class
{
    var setMethod = context.GetType().GetMethod(nameof(DbContext.Set), new Type[] { }).MakeGenericMethod(typeof(TEntity)); //Get Method Set<MyIdentityModel.IdentityRole>
    var dbSet = setMethod.Invoke(context, new object[] { }); // Calling context.Set<MyIdentityModel.IdentityRole>
    /* Call to another methods using reflection before calling "ToList" 
        Eg. example Where, Include, Select
        */
    var toListMethod = typeof(Enumerable).GetMethod("ToList").MakeGenericMethod(typeof(TEntity)); //get Extension Method "ToList<MyIdentityModel.IdentityRole>"
    var list = (List<TEntity>)toListMethod.Invoke(null, new object[] { dbSet });//Calling "context.Set<MyIdentityModel.IdentityRole>.ToList<MyIdentityModel.IdentityRole>()" Method and convert to destination type if is possible.
    return list;
}

public List<TEntity> GetList3<TEntity>(DbContext context)
    where TEntity : class
{
    return context.Set<TEntity>()/* Call to another methods before "ToList" */.ToList();
}


主程序调用。

  1. 您需要上下文,AssemblyQualifiedName = 参数。结果的类型名称= 类型参数

public List<TResult> GetList<TResult>(DbContext context, string entityTypeName)

  1. 您需要上下文= 参数。结果的类型名称= 类型参数

public List<TEntity> GetList2<TEntity>(DbContext context)

  1. 您需要上下文= 参数。结果的类型名称= 类型参数

public List<TEntity> GetList3<TEntity>(DbContext context)

Console.WriteLine("█ Result 1");
var result = GetList<MyIdentityModel.IdentityRole>(context, typeof(MyIdentityModel.IdentityRole).AssemblyQualifiedName);
Console.WriteLine(JsonSerializer.Serialize(result));
Console.WriteLine();

Console.Write("█ Result 2");
var result2 = GetList2<MyIdentityModel.IdentityRole>(context);
Console.WriteLine(JsonSerializer.Serialize(result2));
Console.WriteLine();

Console.Write("█ Result 3");
var result3 = GetList3<MyIdentityModel.IdentityRole>(context);
Console.WriteLine(JsonSerializer.Serialize(result3));
Console.WriteLine();

其他类似于Where的方法你会如何称呼? - GidiBloke
你会怎么称呼其他方法,比如Where? - undefined

0

您可以像下面这样使用泛型类型

DbContext.Set<T>().Select(e => e);

但是为了实现这一点,您的方法应该像下面的示例一样使用泛型(此代码未经测试):

public Task<object> MyMethod<T>(T model)
{
   // some Code
}

你可以在这个链接中了解更多相关信息。

抱歉我的英语不太好。 希望它能有所帮助...


0
创建一个虚拟实例来欺骗泛型方法的绑定。
public IEnumerable<T> GetEntity<T>() where T : class
{
    Type type = typeof(T);
    Type spoofedType = typeof(InternalDbSet<>).MakeGenericType(type);
    //instance is only used to spoof the binding
    dynamic instance = Activator.CreateInstance(spoofedType, context, spoofedType.Name);
    return SpoofedMethod(instance);
}

public IEnumerable<T> SpoofedMethod<T>(DbSet<T> _) where T : class
{
     return context.Set<T>().Select(e => e);
}

Activator.CreateInstance接受类型并将其余参数传递给该类型的构造函数。InternalDbSet<>需要两个参数:DbContext和EntityTypeName。DbSet本身是一个抽象类,因此无法创建其实例。如果你在运行时检查一个DbSet的类型,那么你会看到它是InternalDbSet。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接