You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 6中EF Core DbContext导出表到CSV遇DbSet构造函数缺失异常

Blazor ASP.NET Core提取DbSet导出CSV时的构造函数缺失异常修复方案

我需要开发一个Blazor ASP.NET Core应用,把MS SQL Server数据库的每张表导出为独立的.csv文件。我尝试从DbContext的属性中提取DbSet到泛型列表,但在将泛型对象转换为DbSet类时出现了以下异常:

An unhandled exception occurred while processing the request.
MissingMethodException: Constructor on type
'Microsoft.EntityFrameworkCore.DbSet`1[[DatabaseTableExport.Data.LoginDbModels.AccountPasswordHistory,
DatabaseTableExport, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null]]' not found.
System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder
binder, object[] args, CultureInfo culture)

请问如何修复这个错误,或者有没有更好的从DbContext提取DbSet的方法?

用户提供的代码:

using DatabaseTableExport.Data;
using DatabaseTableExport.Data.LoginDbModels;
using Microsoft.AspNetCore.Components;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace DatabaseTableExport.Pages
{
    public partial class Index : ComponentBase
    {
        [Inject]
        private LoginDbContext LoginDbContext { get; set; }
        [Inject]
        private ApplicationDbContext ApplicationDbContext { get; set; }

        protected override void OnInitialized()
        {
            List<DbSet<object>> dbSets = GetDbSets(LoginDbContext);

            // iterate through each DbSet instance
            foreach (var dbSet in dbSets)
            {
                // export to csv here
            }

        }

        private static List<DbSet<object>> GetDbSets(DbContext loginDbContext)
        {
            // Retrieve all the DbSet properties declared on the context class.
            var dbSetProperties = loginDbContext.GetType()
                .GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
                .Where(p => p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>))
                .ToList();

            // Iterate over each DbSet property and add it to the list of dbsets.
            var dbSets = new List<DbSet<object>>();
            foreach (var property in dbSetProperties)
            {
                // If the type of the DbSet is null, skip it.
                if (property.PropertyType.GenericTypeArguments.Length <= 0)
                {
                    continue;
                }

                // Get the generic type arguments and create a corresponding DbSet instance.
                var dbsetGenericType = property.PropertyType.GenericTypeArguments[0];
                var convertedDbSet = Activator.CreateInstance(typeof(DbSet<>).MakeGenericType(dbsetGenericType), property.GetValue(loginDbContext));

                dbSets.Add((DbSet<object>)convertedDbSet);
            }

            // Return the list of DbSet objects.
            return dbSets;
        }
    }
}

错误原因

核心问题是DbSet没有公开的构造函数,无法通过Activator.CreateInstance直接创建实例。而且DbContext中定义的DbSet属性本身已经是EF Core初始化好的实例,完全不需要重新创建,只需直接获取这些实例并转换为通用类型即可。

修复后的GetDbSets方法

修改GetDbSets方法,跳过不必要的实例创建步骤,直接获取DbContext中已有的DbSet实例:

private static List<DbSet<object>> GetDbSets(DbContext dbContext)
{
    var dbSetProperties = dbContext.GetType()
        .GetProperties(BindingFlags.Public | BindingFlags.Instance)
        .Where(p => p.PropertyType.IsGenericType 
                    && p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>))
        .ToList();

    var dbSets = new List<DbSet<object>>();
    foreach (var property in dbSetProperties)
    {
        // 直接获取DbContext中已有的DbSet实例
        var dbSetInstance = property.GetValue(dbContext);
        // 将DbSet<T>转为DbSet<object>
        var objectDbSet = (DbSet<object>)typeof(DbSet<>).MakeGenericType(
            property.PropertyType.GenericTypeArguments[0])
            .GetMethod("AsQueryable")?
            .Invoke(dbSetInstance, null);
        
        if (objectDbSet != null)
        {
            dbSets.Add(objectDbSet);
        }
    }
    return dbSets;
}

更优的处理方式

如果仅需导出CSV,无需强行转换成DbSet<object>,用IQueryable<object>处理更简洁:

private static IEnumerable<(Type EntityType, IQueryable<object> Data)> GetDbSetData(DbContext dbContext)
{
    foreach (var property in dbContext.GetType()
        .GetProperties(BindingFlags.Public | BindingFlags.Instance)
        .Where(p => p.PropertyType.IsGenericType 
                    && p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>)))
    {
        var entityType = property.PropertyType.GenericTypeArguments[0];
        var dbSet = property.GetValue(dbContext);
        var queryable = (IQueryable<object>)typeof(Queryable)
            .GetMethod("AsQueryable")
            .MakeGenericMethod(entityType)
            .Invoke(null, new[] { dbSet });
        
        yield return (entityType, queryable);
    }
}

使用示例:

protected override void OnInitialized()
{
    var dbSetDataList = GetDbSetData(LoginDbContext).ToList();

    foreach (var (entityType, data) in dbSetDataList)
    {
        // 用实体类型名作为CSV文件名
        string fileName = $"{entityType.Name}.csv";
        // 获取所有数据行
        var records = data.ToList();
        // 执行CSV导出逻辑
    }
}

补充说明

  • 移除BindingFlags.DeclaredOnly可获取DbContext基类中定义的DbSet,若仅需当前类定义的DbSet可保留该标记。
  • 导出CSV时,可通过反射获取实体属性名作为表头,遍历实体对象获取属性值生成行数据。

内容的提问来源于stack exchange,提问作者Tyson Gibby

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 11:05:53