C# EF Core:如何以编程方式访问数据库集以用于种子目的
在EF Core 3.1+中,我想使用C# EF Core:如何以编程方式访问数据库集以用于种子目的,c#,entity-framework,entity-framework-core,seeding,C#,Entity Framework,Entity Framework Core,Seeding,在EF Core 3.1+中,我想使用seed()扩展方法以编程方式从任何DbContext中为所有数据库集设置种子,并使用数据。Seed()方法在非动态情况下运行良好 对于手动解决方案,我可以添加代码(可以为每个实体添加记录),如: 对于适用于任何DbContext的动态解决方案,我的方法是这样的代码: var entityTypes = myContext.Model.GetEntityTypes(); foreach (var et in entityTypes) { myCon
seed()
扩展方法以编程方式从任何DbContext中为所有数据库集设置种子,并使用数据。Seed()
方法在非动态情况下运行良好
对于手动解决方案,我可以添加代码(可以为每个实体添加记录),如:
对于适用于任何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);
}
}
你知道如何获得对数据库集的通用编程访问,以便向每个数据库集添加数据吗
==编辑==========================================================
我更新了扩展方法,因为我意识到重复是针对返回的多个方法的,所以我让该部分按如下方式工作。此代码正确返回DBSet(排序):
有什么想法吗?DbContext有多个参数不同的
Set
方法
获得正确的MethodInfo
的简单方法是创建一个匹配的委托
var method=new Func(_context.Set).method.GetGenericMethodDefinition();
MakeGenericMethod(T).Invoke(…);
当然,如果已经为每种类型定义了DbSet属性,则可以循环这些属性
另一个问题是set.ToList().Add(…
)。调用ToList
将整个表加载到一个列表对象中,该对象不知道它来自的数据库集。您需要调用DbSet.Add
,而不是list.Add
我会将您的整个seed方法移动到一个泛型方法中,对每个类型进行泛型,然后调用它
private void Seed(DbContext context,T obj)=>
context.Set.Add(obj);
var method=new Action(Seed.method.GetGenericMethodDefinition();
foreach(entityTypes中的变量et)
MakeGenericMethod(et.ClrType).Invoke(…);
对于EF Core来说,这似乎是一件简单的事情,但事实并非如此,也可能不可能
从这一点来看,最近对EF的修改似乎使这一点变得更加困难
如果您使用“DbContent.Set”通过反射跳转得到一个DbSet列表,您会发现这些实际上是“InternalDbSet”类型,并带有一系列关于不应如何使用它们的警告。无法将它们转换到DbSet或像IDbSet这样的接口
但是如果有人有一个好的解决方案,请发帖,因为我现在很想知道是否可以做到。尝试用
typeof(DbContext)替换\u context.GetType()
。
@ivan stoev-谢谢,但是使用typeof(DbContext)我们仍然会得到同样的错误。EF Core 5.0?关于typeof(DbContext.GetMethod)(nameof(DbContext.Set)呢,键入.EmptyTypes)
然后。关于ToList()的观点很好。我会看一看。谢谢
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);
}
}
Categories.AddRange(Categories.ToList().Seed(10));
Products.AddRange(Products.ToList().Seed(20));
...
SaveChanges();
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);
}
// 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();