How do I fix `System.MissingMethodException: Constructor on type Microsoft.EntityFrameworkCore.DbSet`1 not found.`?

huangapple go评论122阅读模式
英文:

How do I fix `System.MissingMethodException: Constructor on type Microsoft.EntityFrameworkCore.DbSet`1 not found.`?

问题

使用EntityFramework DbContext在.NET 6中将数据库表导出为CSV

我被要求创建一个Blazor ASP.NET Core应用程序,将从MS SQL Server数据库中的每个表导出到自己的.csv文件中。我已将DbContext属性中的DbSets提取到一个通用列表中,但当我尝试将通用对象转换为它们的DbSet类时,出现以下错误:

在处理请求时发生未经处理的异常。
MissingMethodException: 类型 'Microsoft.EntityFrameworkCore.DbSet`1[[DatabaseTableExport.Data.LoginDbModels.AccountPasswordHistory, DatabaseTableExport, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' 上的构造函数未找到。
System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture)

如何修复此错误,或者是否有更好的方法从DbContext中提取DbSets

  1. using DatabaseTableExport.Data;
  2. using DatabaseTableExport.Data.LoginDbModels;
  3. using Microsoft.AspNetCore.Components;
  4. using Microsoft.EntityFrameworkCore;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using System.Reflection;
  9. namespace DatabaseTableExport.Pages
  10. {
  11. public partial class Index : ComponentBase
  12. {
  13. [Inject]
  14. private LoginDbContext LoginDbContext { get; set; }
  15. [Inject]
  16. private ApplicationDbContext ApplicationDbContext { get; set; }
  17. protected override void OnInitialized()
  18. {
  19. List<DbSet<object>> dbSets = GetDbSets(LoginDbContext);
  20. // 遍历每个DbSet实例
  21. foreach (var dbSet in dbSets)
  22. {
  23. // 在这里导出到csv
  24. }
  25. }
  26. private static List<DbSet<object>> GetDbSets(DbContext loginDbContext)
  27. {
  28. // 检索上下文类上声明的所有DbSet属性。
  29. var dbSetProperties = loginDbContext.GetType()
  30. .GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
  31. .Where(p => p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>))
  32. .ToList();
  33. // 遍历每个DbSet属性,并将其添加到dbsets列表中。
  34. var dbSets = new List<DbSet<object>>();
  35. foreach (var property in dbSetProperties)
  36. {
  37. // 如果DbSet的类型为空,请跳过。
  38. if (property.PropertyType.GenericTypeArguments.Length <= 0)
  39. {
  40. continue;
  41. }
  42. // 获取泛型类型参数,并创建相应的DbSet实例。
  43. var dbsetGenericType = property.PropertyType.GenericTypeArguments[0];
  44. var convertedDbSet = Activator.CreateInstance(typeof(DbSet<>).MakeGenericType(dbsetGenericType), property.GetValue(loginDbContext));
  45. dbSets.Add((DbSet<object>)convertedDbSet);
  46. }
  47. // 返回DbSet对象列表。
  48. return dbSets;
  49. }
  50. }
  51. }
英文:

Database Table Export to CSV using EntityFramework DbContext .NET 6

I have been tasked to create a Blazor ASP.NET Core application that will export each table from an MS SQL Server database into it's own .csv file. I have extracted the DbSets from the DbContext properties into a generic list, but when I attempt to cast the generic objects to their DbSet class I get the following error:

> 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)

How do I fix this error, or is there a better way to be extracting the DbSets from the DbContext?

  1. using DatabaseTableExport.Data;
  2. using DatabaseTableExport.Data.LoginDbModels;
  3. using Microsoft.AspNetCore.Components;
  4. using Microsoft.EntityFrameworkCore;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using System.Reflection;
  9. namespace DatabaseTableExport.Pages
  10. {
  11. public partial class Index : ComponentBase
  12. {
  13. [Inject]
  14. private LoginDbContext LoginDbContext { get; set; }
  15. [Inject]
  16. private ApplicationDbContext ApplicationDbContext { get; set; }
  17. protected override void OnInitialized()
  18. {
  19. List&lt;DbSet&lt;object&gt;&gt; dbSets = GetDbSets(LoginDbContext);
  20. // iterate through each DbSet instance
  21. foreach (var dbSet in dbSets)
  22. {
  23. // export to csv here
  24. }
  25. }
  26. private static List&lt;DbSet&lt;object&gt;&gt; GetDbSets(DbContext loginDbContext)
  27. {
  28. // Retrieve all the DbSet properties declared on the context class.
  29. var dbSetProperties = loginDbContext.GetType()
  30. .GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
  31. .Where(p =&gt; p.PropertyType.IsGenericType &amp;&amp; p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet&lt;&gt;))
  32. .ToList();
  33. // Iterate over each DbSet property and add it to the list of dbsets.
  34. var dbSets = new List&lt;DbSet&lt;object&gt;&gt;();
  35. foreach (var property in dbSetProperties)
  36. {
  37. // If the type of the DbSet is null, skip it.
  38. if (property.PropertyType.GenericTypeArguments.Length &lt;= 0)
  39. {
  40. continue;
  41. }
  42. // Get the generic type arguments and create a corresponding DbSet instance.
  43. var dbsetGenericType = property.PropertyType.GenericTypeArguments[0];
  44. var convertedDbSet = Activator.CreateInstance(typeof(DbSet&lt;&gt;).MakeGenericType(dbsetGenericType), property.GetValue(loginDbContext));
  45. dbSets.Add((DbSet&lt;object&gt;)convertedDbSet);
  46. }
  47. // Return the list of DbSet objects.
  48. return dbSets;
  49. }
  50. }
  51. }

答案1

得分: 1

以下是您要翻译的内容:

"EF Core works without DbContext properties. Metadata information can be retrieved from DbContext's Model and Export can be initiated via CallBack."

回调接口:

  1. public interface IRecordsetProcessor
  2. {
  3. void ProcessRecordset&lt;T&gt;(DbContext context, IQueryable&lt;T&gt; recordset, IEntityType entityType)
  4. where T: class;
  5. }

Recordset枚举实现:

  1. public static class DbContextUtils
  2. {
  3. public static void ProcessRecordset&lt;T&gt;(DbContext context, IEntityType entityType, IRecordsetProcessor processor)
  4. where T : class
  5. {
  6. processor.ProcessRecordset(context, context.Set&lt;T&gt;(), entityType);
  7. }
  8. private static MethodInfo _processMethod = typeof(DbContextUtils).GetMethod(nameof(ProcessRecordset))!;
  9. public static void ProcessRecordsets(DbContext context, IRecordsetProcessor processor)
  10. {
  11. var entityTypes = context.Model.GetEntityTypes()
  12. .Where(et =&gt; !et.IsOwned())
  13. .ToList();
  14. foreach (var et in entityTypes)
  15. {
  16. _processMethod.MakeGenericMethod(et.ClrType).Invoke(null, new object[] { context, et, processor });
  17. }
  18. }
  19. }

导出的简单示例实现:

  1. public class ExportProcessor : IRecordsetProcessor
  2. {
  3. private const string ColumnSeparator = &quot;,&quot;
  4. static string PreparePropertyValue(IProperty prop, object record)
  5. {
  6. var clrValue = prop.GetGetter().GetClrValue(record);
  7. // without converter
  8. var value = clrValue;
  9. // with converter
  10. /*
  11. var converter = prop.GetValueConverter();
  12. var value = converter == null ? clrValue : converter.ConvertToProvider(clrValue);
  13. */
  14. if (value == null)
  15. return &quot;&quot;
  16. var strValue = value.ToString() ?? &quot;&quot;
  17. if (strValue.Contains(ColumnSeparator) || strValue.Contains(&#39;\&quot;&#39;))
  18. {
  19. strValue = &quot;\&quot;&quot; + strValue.Replace(&quot;\&quot;&quot;, &quot;\&quot;\&quot;&quot;) + &quot;\&quot;&quot;
  20. }
  21. return strValue;
  22. }
  23. public void ProcessRecordset&lt;T&gt;(DbContext context, IQueryable&lt;T&gt; recordset, IEntityType entityType) where T : class
  24. {
  25. var exportItems = new List&lt;string&gt;();
  26. var properties = entityType.GetProperties().ToList();
  27. // produce header
  28. exportItems.Add(string.Join(ColumnSeparator, properties.Select(p =&gt; p.GetColumnName())));
  29. foreach (var record in recordset.AsNoTracking())
  30. {
  31. exportItems.Add(string.Join(ColumnSeparator, properties.Select(p =&gt; PreparePropertyValue(p, record))));
  32. }
  33. // TODO: save to file, or do that without intermediate list
  34. }
  35. }

使用示例:

  1. DbContextUtils.ProcessRecordsets(context, new ExportProcessor());
英文:

I would suggest different approach. EF Core works without DbContext properties. Metadata information can be retrieved from DbContext's Model and Export can be initiated via CallBack.

Callback interface:

  1. public interface IRecordsetProcessor
  2. {
  3. void ProcessRecordset&lt;T&gt;(DbContext context, IQueryable&lt;T&gt; recordset, IEntityType entityType)
  4. where T: class;
  5. }

Recordset enumeration Implemantation:

  1. public static class DbContextUtils
  2. {
  3. public static void ProcessRecordset&lt;T&gt;(DbContext context, IEntityType entityType, IRecordsetProcessor processor)
  4. where T : class
  5. {
  6. processor.ProcessRecordset(context, context.Set&lt;T&gt;(), entityType);
  7. }
  8. private static MethodInfo _processMethod = typeof(DbContextUtils).GetMethod(nameof(ProcessRecordset))!;
  9. public static void ProcessRecordsets(DbContext context, IRecordsetProcessor processor)
  10. {
  11. var entityTypes = context.Model.GetEntityTypes()
  12. .Where(et =&gt; !et.IsOwned())
  13. .ToList();
  14. foreach (var et in entityTypes)
  15. {
  16. _processMethod.MakeGenericMethod(et.ClrType).Invoke(null, new object[] { context, et, processor });
  17. }
  18. }
  19. }

Simple sample implementation of export:

  1. public class ExportProcessor : IRecordsetProcessor
  2. {
  3. private const string ColumnSeparator = &quot;,&quot;;
  4. static string PreparePropertyValue(IProperty prop, object record)
  5. {
  6. var clrValue = prop.GetGetter().GetClrValue(record);
  7. // without converter
  8. var value = clrValue;
  9. // with converter
  10. /*
  11. var converter = prop.GetValueConverter();
  12. var value = converter == null ? clrValue : converter.ConvertToProvider(clrValue);
  13. */
  14. if (value == null)
  15. return &quot;&quot;;
  16. var strValue = value.ToString() ?? &quot;&quot;;
  17. if (strValue.Contains(ColumnSeparator) || strValue.Contains(&#39;\&quot;&#39;))
  18. {
  19. strValue = &quot;\&quot;&quot; + strValue.Replace(&quot;\&quot;&quot;, &quot;\&quot;\&quot;&quot;) + &quot;\&quot;&quot;;
  20. }
  21. return strValue;
  22. }
  23. public void ProcessRecordset&lt;T&gt;(DbContext context, IQueryable&lt;T&gt; recordset, IEntityType entityType) where T : class
  24. {
  25. var exportItems = new List&lt;string&gt;();
  26. var properties = entityType.GetProperties().ToList();
  27. // produce header
  28. exportItems.Add(string.Join(ColumnSeparator, properties.Select(p =&gt; p.GetColumnName())));
  29. foreach (var record in recordset.AsNoTracking())
  30. {
  31. exportItems.Add(string.Join(ColumnSeparator, properties.Select(p =&gt; PreparePropertyValue(p, record))));
  32. }
  33. // TODO: save to file, or do that without intermediate list
  34. }
  35. }

Usage sample:

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

huangapple
  • 本文由 发表于 2023年7月31日 23:58:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/76805286.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定