EF从Type中获取运行时记录列表

目的:我需要循环所有记录,如:

var records = db.Set().ToList(); 

然后循环

 foreach (var record in records) { // do something with the record } 

但是它必须在运行时没有特定类型,因为我要遍历类型,因此不知道示例“UserAccount”。 只有Type / TypeOf?

在本说明书的底部,我有一个方法loopAllEntities ,我找不到工作方式

我用一些实体创建了一个DbContext。

 public class MyEntities : DbContext { public DbSet UserAccounts { get; set;} public DbSet UserRoles { get; set; } public DbSet UserAccountRoles { get; set; } } 

定义了一个Type列表来控制输出:

 public static List ModelListSorted() { List modelListSorted = new List(); modelListSorted.Add(typeof(UserRole)); modelListSorted.Add(typeof(UserAccountRole)); modelListSorted.Add(typeof(UserAccount)); return modelListSorted; } 

问题是在我无法找到使其工作的方法:-(

 public static loopAllEntities() { List modelListSorted = ModelHelper.ModelListSorted(); foreach (Type type in modelListSorted) { var records = ????? // get a list of records in the current table from type. foreach (var record in records) { // do something with the record } } } 

看起来你几乎就在那里,你应该可以做如下的事情:

  public static void loopAllEntities(DbContext dbContext) { List modelListSorted = ModelHelper.ModelListSorted(); foreach (Type type in modelListSorted) { var records = dbContext.Set(type); // do something with the set here } } 

这将为您提供一个非generics集合。 它取决于你想要做什么,因为这个集合没有类型它可能会有点棘手,可能会转换为基本类型或接口使用?

编辑:我没有足够的声誉来评论,但是Mayoors解决方案可以在不使用非generics类型的情况下获得您想要的内容并预先获得整个集合。

我最初认为你不能只获得一种类型的实体,但是看看Matt的答案,你可以。 所以,这个答案可能不是最好的答案……

基本思想是获取IEnumerable的列表,其中每个IEnumerable是我们模型中的Entity。 我们必须使用普通旧object的原因是因为我们希望它返回彼此不相关的不同实体。 但是,这并不是那么糟糕,因为当你循环遍历每个对象时,如果需要,可以将它转换为某个实体。

首先,我们将创建一个返回此列表的方法:

 private static List> AllEntities(MyEntities db) { List> list = new List>(); list.Add(db.UserRole); list.Add(db.UserAccountRole); list.Add(db.UserAccount); return list; } 

我们传入DbContext因为当我们实际开始循环遍历此方法之外的IEnumerables时它会被使用。 所以,我们不能在这里创建DbContext然后Dispose它。

我们现在可以使用此方法遍历所有实体:

 using (var db = GetMyEntities()) { List> recordsList = AllEntities(db); foreach (IEnumerable records in recordsList) { foreach (object record in records) { // Do something with record. // If you need to access type-specific properties, // do something like below if (record is UserAccount) { UserAccount account = (UserAccount)record; Console.WriteLine("User Name: " + account.UserName); } } } } 

就是这样。 就SQL而言,对于外部foreach循环的每次迭代,它将执行SELECT * FROM TABLE_NAME之类的操作。 这意味着它不会缓存List> ,并且每次使用AllEntities它都会从数据库中获取新数据。

我知道这是一个老问题,但问题并没有指定EF版本,并且提议的答案不再适用于Entity Framework Core(DbContext在EF核心中至少在此答案的日期没有非通用的set方法) 。

然而,你仍然可以使用Jon Skeet的答案来解决这个问题 。 为方便起见,我的代码在下面添加。

  public static IQueryable Set(this DbContext context, Type T) { // Get the generic type definition MethodInfo method = typeof(DbContext).GetMethod(nameof(DbContext.Set), BindingFlags.Public | BindingFlags.Instance); // Build a method with the specific type argument you're interested in method = method.MakeGenericMethod(T); return method.Invoke(context, null) as IQueryable; }