使用内置 Linq to SQL 驱动程序在 LinqPad 中进行 运行 Entity Framework 核心查询的更简单方法?
Easier way to run Entity Framework Core queries in LinqPad with builtin Linq to SQL driver?
注:这是个老问题。对于 LinqPad 5,您有我在下面描述的限制,因为它不是用 .NET Core 编写的。但现在您可以使用较新的 LinqPad 6 or 7,它完全支持 Entity Framework 核心,包括用于多个数据库系统的驱动程序。
我想分析Entity Framework核心查询,我从现有代码复制到LinqPad中,比如
UserQuery this_context;
void Main()
{
this_context = this;
var validationResult = (
from ProjectInfo pi in this_context.GetAll<ProjectInfo>()
join GeneralInformation gi in this_context.GetAll<GeneralInformation>()
on pi.Id equals gi.Id into gpi
from gps in gpi.DefaultIfEmpty()
select new { ... }).ToList();
}
我知道,Linqpad 不支持 .NET Core, 所以我必须稍微调整一下 - 为此,我创建了一个扩展方法,如下所示:
public static class Ext
{
public static IEnumerable GetAll<T>(this UserQuery uq)
where T: new()
{
return GetAll(uq, new T());
}
private static IEnumerable GetAll<T>(this UserQuery uq, T a)
{
switch (a)
{
case ProjectInfo v:
return uq.ProjectInfo.Select(s => s);
case GeneralInformation v:
return uq.GeneralInformation.Select(s => s);
// ... many more cases like the above
default: // unknown type
throw new TypeAccessException($"Unsupported type {a.GetType().FullName}");
}
}
}
需要重载的GetAll
函数来获取类型——它只是创建一个空的新对象并将其传入,以便switch语句可以正确地推导出正确的类型和return正确的查询。
效果很好,但是 需要付出很多努力 才能将每种类型都放入 switch 语句中。
所以我的问题是:
如何以更智能的方式实现这一点,即不必指定每个实体类型?
LINQPad 的 UserQuery
对象似乎有一个方法正是您想要的:
public static class Ext {
public static IEnumerable GetAll<T>(this UserQuery uq) =>uq.GetTable(typeof(T));
}
我相信您可以通过以下方式保持类型安全:
public static IQueryable<T> GetAll<T>(this UserQuery uq) => (IQueryable<T>)uq.GetTable(typeof(T));
使用您原来的 IEnumerable
版本会导致所有表被一个接一个地加载到内存中,然后在对象上执行 LINQ。使用 IQueryable<T>
将查询转换为 SQL - 在 LINQ to SQL 和 EF 的翻译不同(没有充分理由)的情况下,这可能是不可取的,但我可以看到问题EF 特定功能(例如 Include
和 DbFunctions
,尽管我写了空的 Include
扩展方法来隐藏一些)。
如果 IQueryable
版本不起作用,ITable<>
版本可能:
public static ITable<T> GetAll<T>(this UserQuery uq) where T : class => (ITable<T>)uq.GetTable(typeof(T));
注:这是个老问题。对于 LinqPad 5,您有我在下面描述的限制,因为它不是用 .NET Core 编写的。但现在您可以使用较新的 LinqPad 6 or 7,它完全支持 Entity Framework 核心,包括用于多个数据库系统的驱动程序。
我想分析Entity Framework核心查询,我从现有代码复制到LinqPad中,比如
UserQuery this_context;
void Main()
{
this_context = this;
var validationResult = (
from ProjectInfo pi in this_context.GetAll<ProjectInfo>()
join GeneralInformation gi in this_context.GetAll<GeneralInformation>()
on pi.Id equals gi.Id into gpi
from gps in gpi.DefaultIfEmpty()
select new { ... }).ToList();
}
我知道,Linqpad 不支持 .NET Core, 所以我必须稍微调整一下 - 为此,我创建了一个扩展方法,如下所示:
public static class Ext
{
public static IEnumerable GetAll<T>(this UserQuery uq)
where T: new()
{
return GetAll(uq, new T());
}
private static IEnumerable GetAll<T>(this UserQuery uq, T a)
{
switch (a)
{
case ProjectInfo v:
return uq.ProjectInfo.Select(s => s);
case GeneralInformation v:
return uq.GeneralInformation.Select(s => s);
// ... many more cases like the above
default: // unknown type
throw new TypeAccessException($"Unsupported type {a.GetType().FullName}");
}
}
}
需要重载的GetAll
函数来获取类型——它只是创建一个空的新对象并将其传入,以便switch语句可以正确地推导出正确的类型和return正确的查询。
效果很好,但是 需要付出很多努力 才能将每种类型都放入 switch 语句中。
所以我的问题是:
如何以更智能的方式实现这一点,即不必指定每个实体类型?
LINQPad 的 UserQuery
对象似乎有一个方法正是您想要的:
public static class Ext {
public static IEnumerable GetAll<T>(this UserQuery uq) =>uq.GetTable(typeof(T));
}
我相信您可以通过以下方式保持类型安全:
public static IQueryable<T> GetAll<T>(this UserQuery uq) => (IQueryable<T>)uq.GetTable(typeof(T));
使用您原来的 IEnumerable
版本会导致所有表被一个接一个地加载到内存中,然后在对象上执行 LINQ。使用 IQueryable<T>
将查询转换为 SQL - 在 LINQ to SQL 和 EF 的翻译不同(没有充分理由)的情况下,这可能是不可取的,但我可以看到问题EF 特定功能(例如 Include
和 DbFunctions
,尽管我写了空的 Include
扩展方法来隐藏一些)。
如果 IQueryable
版本不起作用,ITable<>
版本可能:
public static ITable<T> GetAll<T>(this UserQuery uq) where T : class => (ITable<T>)uq.GetTable(typeof(T));