我的任务是创建一个Blazor ASP.NET Core应用程序,该应用程序将每个表从MS SQL Server数据库导出到它自己的.csv文件中.我已经将DbContext个属性中的DbSets提取到泛型列表中,但是当我try 将泛型对象转换为它们的DbSet类时,我得到了以下错误:

处理请求时出现未处理的异常. Missing方法异常:类型上的构造函数 ‘Microsoft.EntityFrameworkCore.DbSet`1[[DatabaseTableExport.Data.LoginDbModels.AccountPasswordHistory, 数据库表导出,版本=1.0.0.0,区域性=中性, 找不到PublicKeyToken=NULL]]‘. System.RuntimeType.CreateInstanceImpl(BindingFlags绑定属性,活页夹 活页夹,对象[]参数,文化信息区域性)

我如何修复这个错误,或者有没有更好的方法从DbContext中提取DbSets

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;
        }
    }
}

推荐答案

我会建议采取不同的方法.EF Core在没有DbContext个属性的情况下工作.元数据信息可以从DbContext的Model中获取,并且可以通过回调发起导出.

回调接口:

public interface IRecordsetProcessor
{
    void ProcessRecordset<T>(DbContext context, IQueryable<T> recordset, IEntityType entityType)
        where T: class;
}

记录集枚举实现:

public static class DbContextUtils
{
    public static void ProcessRecordset<T>(DbContext context, IEntityType entityType, IRecordsetProcessor processor) 
        where T : class
    {
        processor.ProcessRecordset(context, context.Set<T>(), entityType);
    }

    private static MethodInfo _processMethod = typeof(DbContextUtils).GetMethod(nameof(ProcessRecordset))!;

    public static void ProcessRecordsets(DbContext context, IRecordsetProcessor processor)
    {
        var entityTypes = context.Model.GetEntityTypes()
            .Where(et => !et.IsOwned())
            .ToList();

        foreach (var et in entityTypes)
        {
            _processMethod.MakeGenericMethod(et.ClrType).Invoke(null, new object[] { context, et, processor });
        }
    }
}

导出的简单示例实现:

public class ExportProcessor : IRecordsetProcessor
{
    private const string ColumnSeparator = ",";

    static string PreparePropertyValue(IProperty prop, object record)
    {
        var clrValue = prop.GetGetter().GetClrValue(record);

        // without converter
        var value = clrValue;

        // with converter
        /*
        var converter = prop.GetValueConverter();
        var value = converter == null ? clrValue : converter.ConvertToProvider(clrValue);
        */
        
        if (value == null)
            return "";
        var strValue = value.ToString() ?? "";

        if (strValue.Contains(ColumnSeparator) || strValue.Contains('\"'))
        {
            strValue = "\"" + strValue.Replace("\"", "\"\"") + "\"";
        }

        return strValue;
    }

    public void ProcessRecordset<T>(DbContext context, IQueryable<T> recordset, IEntityType entityType) where T : class
    {
        var exportItems = new List<string>();
        var properties = entityType.GetProperties().ToList();

        // produce header
        exportItems.Add(string.Join(ColumnSeparator, properties.Select(p => p.GetColumnName())));

        foreach (var record in recordset.AsNoTracking())
        {
            exportItems.Add(string.Join(ColumnSeparator, properties.Select(p => PreparePropertyValue(p, record))));
        }

        // TODO: save to file, or do that without intermediate list
    }
}

使用示例:

DbContextUtils.ProcessRecordsets(context, new ExportProcessor());

Csharp相关问答推荐

当前文化和当前文化之间没有区别IgnoreCase,为什么?

当我 for each 请求创建实例时,我是否应该在C#中部署httpClient?

后台线程上的延迟WriteableBitmap写入导致闪烁

如果第一个匹配项为空,则规则运算不会拆分C#中分离字符串上的子菜单

获取Windows和Linux上的下载文件夹

Plotly.NET访问互联网时出现异常

在Dapper中使用IasyncEum重写GetAsyncEum方法

如果存在对CodeAnalysis.CSharp的引用,则不能引用netStandard2.0库

在发布表单时绑定包含附加(嵌套)列表的对象列表的正确语法是什么

使页面内容居中

如何解决提交按钮后 Select 选项错误空参照异常

我的MRG32k3a算法实现返回的数字超出了预期的[0,1]范围

有没有类似于扩展元素的合并元组的语法?

正在寻找新的.NET8 Blazor Web应用程序.如何将.js添加到.razor页面?

HelperText属性不支持复杂内容(混合C#和标记)

.NET 6:如何防止系统生成的日志(log)?

如何使用EPPlus C#在单个单元格中可视化显示多行文字

是否可以从IQueryable T中获取一个IdentyEntry T>

我应该为C#12中的主构造函数参数创建私有属性吗?

项目参考和方法签名问题