【发布时间】:2021-03-11 03:01:29
【问题描述】:
在 EF Core 3.1+ 中,我想使用 Seed() 扩展方法以编程方式为任何 DbContext 中的所有 DBSet 播种数据。 Seed() 方法在非动态情况下运行良好。
对于手动解决方案,我可以添加代码(可以为每个实体添加记录),例如:
Categories.AddRange(Categories.ToList().Seed(10));
Products.AddRange(Products.ToList().Seed(20));
...
SaveChanges();
我对适用于任何 DbContext 的动态解决方案的方法是这样的代码:
var entityTypes = myContext.Model.GetEntityTypes();
foreach (var et in entityTypes)
{
myContext.Set(et.ClrType).ToList().Seed();
}
那是引用一个扩展方法:
public static class Queryables
{
public static IQueryable<object> Set(this DbContext _context, Type t)
{
return (IQueryable<object>)_context.GetType()
.GetMethod("Set")
.MakeGenericMethod(t)
.Invoke(_context, null);
}
}
但返回错误:
System.Reflection.AmbiguousMatchException: '发现不明确的匹配。'
这是一个使用 EF 3.1+ 的通用解决方案,我想循环遍历当前上下文中的任何 DbSet 并为其播种。
我可以手动添加代码(可以为每个实体添加记录),例如:
Categories.AddRange(Categories.ToList().Seed(10));
Products.AddRange(Products.ToList().Seed(20));
...
SaveChanges();
知道如何获得对 DBSet 的通用编程访问,以便我可以向每个 DBSet 添加数据吗?
===编辑============================================ ===============
我更新了扩展方法,因为我意识到重复是针对返回的多个方法,所以我让该部分按如下方式工作。此代码正确返回 DBSet(有点):
public static IQueryable<object> Set(this DbContext _context, Type T)
{
return (IQueryable<object>)_context.GetType()
.GetMethods()
.First(p => p.Name == "Set" && p.ContainsGenericParameters)
.MakeGenericMethod(T)
.Invoke(_context, null);
}
现在代码运行没有抛出错误,但没有添加项目。
简化代码以便 Seed() 函数不是一个因素,我决定只添加一条记录进行测试,如下所示。我可以看到 DBSet 但仍然没有新记录。
// Does no throw an error but does not add the item
dynamic newItem = Activator.CreateInstance(et.ClrType);
var set = myContext.Set(et.ClrType);
set.ToList().Add(newItem); // Simplified from .Seed();
对此有什么想法吗?
【问题讨论】:
-
尝试用
typeof(DbContext)替换_context.GetType() -
@ivan-stoev - 谢谢,但是使用 typeof(DbContext) 我们仍然会遇到同样的错误。
-
EF Core 5.0?那么
typeof(DbContext).GetMethod(nameof(DbContext.Set), Type.EmptyTypes)怎么样。
标签: c# entity-framework entity-framework-core seeding