使用表的字符串名称从 Entity Framework 动态加载表
Dynamically load tables from Entity Framework with string name of tables
假设我有一个字符串列表,表示生成的 类 的名称,其中 Entity Framework 来自 SQL 服务器:
public static List<string> tableList = new List<string>
{
"aaa",
"bbb",
"ccc",
"ddd",
"eee",
};
我想从实体加载数据:
DateTime from_date = DateTime.MinValue;
DateTime to_date = DateTime.MaxValue;
using (var ctx = new MyEntities())
{
IList<aaa> aa = ctx.aaa
.Where(a => a.date_added >= from_date &&
a.date_added <= to_date)
.ToList();
}
但我必须用 20 个或更多 tables 来做到这一点。
有什么方法可以动态地做到这一点吗?喜欢:
Result res = new Result();
List<Result> r = new List<>();
foreach (string table in tableList)
{
using (var ctx = new MyEntities())
{
IList<*table*> aa = ctx.*table*
.Where(a => a.date_added >= from_date &&
a.date_added <= to_date)
.ToList();
res.quantity = aa.Count();
res.title = table;
}
r.Add(res);
}
所有需要的 table 都有列 date_added
。
PS:我只需要计算在定义的时间段内每个 table 中有多少行。比如tables client, customer, employee: 2020年到2021年注册了多少人,我会输出:
{
"title":"Client",
"quantity": 19,
"from_date": [some_date],
"to_date": [some_date]
},
{
"title":"Customer",
"quantity": 123,
"from_date": [some_date],
"to_date": [some_date]
},
{
"title":"Employee",
"quantity": 31,
"from_date": [some_date],
"to_date": [some_date]
},
考虑到您对我的评论的回答,您可以将 classes 添加到 classes 由 EF 生成的命名空间。我建议您在该名称空间中创建一个新接口,如下所示:
public interface IObjectWithDates
{
DateTime date_added { get; }
}
现在我们希望生成的 classes 具有 date_added 字段来实现 IObjectWithDates 接口。除了修改生成的 classes,您还可以在同一命名空间中添加一个带有
的附加文件
public partial class Client: IObjectWithDates
{ }
public partial class Customer: IObjectWithDates
{ }
//and so on with the classes you want to track
现在我们有一个程序集,其中一些 classes 实现了 IObjectWithDates。如果愿意,您可以使用 Type t = Type.GetType(...)
通过名称获取课程。您还可以要求 C# 为您提供在您的模型命名空间中实现 IObjectWithDates 的所有 classes :
public IEnumerable<Type> AllTrackedClassesInNameSpace(string namespaceName, Assembly assembly)
{
return assembly.GetTypes()
.Where(x => ((!string.IsNullOrWhiteSpace(x.Namespace)) && (x.Namespace.ToUpper().Contains(namespaceName.ToUpper()))))
.Where(x => x.IsClass)
.Where(x=>typeof(IObjectWithDates).IsAssignableFrom(x));
}
[此处编辑]
此时,您将拥有一个类型列表(以下代码中的IEnumerable<Type> typeList
),所有类型都实现了 IObjectWithDates,您应该能够做到这一点:
public int MyCount<T>(DbContext ctx) where T: class, IObjectWithDates
{
return ctx.Set<T>().Count(a => a.date_added >= from_date && a.date_added <= to_date);
}
然后
Result res = new Result();
List<Result> r = new List<Result>();
using (var ctx = new DbContext(""))
{
foreach (var type in typeList)
{
var method = this.GetType().GetMethod("MyCount").MakeGenericMethod(type);
res.quantity = (int)method.Invoke(this, new object[]{ ctx });
res.title = table;
}
r.Add(res);
}
一些细节可能需要调整(from_date / to_date 可能是 MyCount 的参数或调用 class 的属性),但全局思想就在那里。您可以通过反射在上下文中获取 Set<>() 方法,但在我看来,单独的方法更易于阅读和调试。
请注意,生成对象的 IList<> 只是为了计算它们是不明智的,因为 SQL 将请求所有对象,然后 EF 将在每行上实例化很多实例...只是为了计算它们而不是使用 Select Count...
假设我有一个字符串列表,表示生成的 类 的名称,其中 Entity Framework 来自 SQL 服务器:
public static List<string> tableList = new List<string>
{
"aaa",
"bbb",
"ccc",
"ddd",
"eee",
};
我想从实体加载数据:
DateTime from_date = DateTime.MinValue;
DateTime to_date = DateTime.MaxValue;
using (var ctx = new MyEntities())
{
IList<aaa> aa = ctx.aaa
.Where(a => a.date_added >= from_date &&
a.date_added <= to_date)
.ToList();
}
但我必须用 20 个或更多 tables 来做到这一点。
有什么方法可以动态地做到这一点吗?喜欢:
Result res = new Result();
List<Result> r = new List<>();
foreach (string table in tableList)
{
using (var ctx = new MyEntities())
{
IList<*table*> aa = ctx.*table*
.Where(a => a.date_added >= from_date &&
a.date_added <= to_date)
.ToList();
res.quantity = aa.Count();
res.title = table;
}
r.Add(res);
}
所有需要的 table 都有列 date_added
。
PS:我只需要计算在定义的时间段内每个 table 中有多少行。比如tables client, customer, employee: 2020年到2021年注册了多少人,我会输出:
{
"title":"Client",
"quantity": 19,
"from_date": [some_date],
"to_date": [some_date]
},
{
"title":"Customer",
"quantity": 123,
"from_date": [some_date],
"to_date": [some_date]
},
{
"title":"Employee",
"quantity": 31,
"from_date": [some_date],
"to_date": [some_date]
},
考虑到您对我的评论的回答,您可以将 classes 添加到 classes 由 EF 生成的命名空间。我建议您在该名称空间中创建一个新接口,如下所示:
public interface IObjectWithDates
{
DateTime date_added { get; }
}
现在我们希望生成的 classes 具有 date_added 字段来实现 IObjectWithDates 接口。除了修改生成的 classes,您还可以在同一命名空间中添加一个带有
的附加文件public partial class Client: IObjectWithDates
{ }
public partial class Customer: IObjectWithDates
{ }
//and so on with the classes you want to track
现在我们有一个程序集,其中一些 classes 实现了 IObjectWithDates。如果愿意,您可以使用 Type t = Type.GetType(...)
通过名称获取课程。您还可以要求 C# 为您提供在您的模型命名空间中实现 IObjectWithDates 的所有 classes :
public IEnumerable<Type> AllTrackedClassesInNameSpace(string namespaceName, Assembly assembly)
{
return assembly.GetTypes()
.Where(x => ((!string.IsNullOrWhiteSpace(x.Namespace)) && (x.Namespace.ToUpper().Contains(namespaceName.ToUpper()))))
.Where(x => x.IsClass)
.Where(x=>typeof(IObjectWithDates).IsAssignableFrom(x));
}
[此处编辑]
此时,您将拥有一个类型列表(以下代码中的IEnumerable<Type> typeList
),所有类型都实现了 IObjectWithDates,您应该能够做到这一点:
public int MyCount<T>(DbContext ctx) where T: class, IObjectWithDates
{
return ctx.Set<T>().Count(a => a.date_added >= from_date && a.date_added <= to_date);
}
然后
Result res = new Result();
List<Result> r = new List<Result>();
using (var ctx = new DbContext(""))
{
foreach (var type in typeList)
{
var method = this.GetType().GetMethod("MyCount").MakeGenericMethod(type);
res.quantity = (int)method.Invoke(this, new object[]{ ctx });
res.title = table;
}
r.Add(res);
}
一些细节可能需要调整(from_date / to_date 可能是 MyCount 的参数或调用 class 的属性),但全局思想就在那里。您可以通过反射在上下文中获取 Set<>() 方法,但在我看来,单独的方法更易于阅读和调试。
请注意,生成对象的 IList<> 只是为了计算它们是不明智的,因为 SQL 将请求所有对象,然后 EF 将在每行上实例化很多实例...只是为了计算它们而不是使用 Select Count...