将选定的 T 属性从一个 IQueryable<T> 获取到一个 IQueryable<MyClass>
Get Selected T proprties from one IQueryable<T> into an IQueryable<MyClass>
我有一个包含 IQueryable<T>
的通用函数,其中每一行都包含一个具有一组属性的 class 实例。
我有另一个 class (MyClass),它与上面的 class T 具有一些相同的属性...即相同的名称和数据类型。
我还有一个字符串列表,其中包含两个 class 之间共享的 属性 名称。
我希望能够创建一个新的 IQueryable<myClass>
,其中 myClass 实例属性填充了原始 IQueryable<T>
中的同名属性
这有意义吗?请让我知道我是否可以提供更多信息或使任何内容更清楚。
编辑
我会尝试添加一些代码来更好地说明。我知道这里有无数错误,包括添加到 IQueryable - 但这是为了说明:
IQueryable<T> qry = this.GetSomeDataIntoIQueryable();
// Just getting a list of the Shared Property Names between the two classes
List<string> sharedProprtyNames = new List<string>();
foreach (var item in ListofSharedPropertyNames)
{
sharedProprtyNames .Add(item.SharedPropertyName);
}
IQueryable<myClass> myClassIQ;
foreach(var classItem in qry)
{
myClass x = new myClass();
foreach(var sharedProperty in sharedProprtyNames )
{
myClass[sharedProperty] = classItem[sharedProperty];
}
myClassIQ.Add(myClass);
}
使用System.Linq.Dynamic.Core
您可以:
IQueryable<Table1> query1 = ...
var res = query.Select<SubTable1>("new(" + string.Join(",", new[] { "Col1", "Col2" }) + ")").ToArray();
其中query1
是您的查询,Table1
是您问题的T
,SubTable1
是MyClass
,"Col1", "Col2"
是必须选择的列。
你可以在不使用 System.Linq.Dynamic.Core
库和简单地构建表达式树的情况下做任何事情......但这很痛苦:-)
我对 Hans Passant 代码的变体:
public static IQueryable<TResult> Select<TSource, TResult>(this IQueryable<TSource> source, IEnumerable<string> columns)
{
// the x in x => ...
var par = Expression.Parameter(typeof(TSource), "x");
// "Bindings" (the Col1 = x.Col1 inside the x => new { Col1 = x.Col1 })
var binds = columns.Select(x => Expression.Bind((MemberInfo)typeof(TResult).GetProperty(x) ?? typeof(TResult).GetField(x), Expression.PropertyOrField(par, x)));
// new TResult
var new1 = Expression.New(typeof(TResult));
// new TResult { Bindings }
var mi = Expression.MemberInit(new1, binds);
// x => new TResult { Bindings }
var lambda = Expression.Lambda<Func<TSource, TResult>>(mi, par);
// Select(x => new TResult { Bindings })
return source.Select(lambda);
}
(几乎完全等同...唯一的区别是他使用GetMember()
而我使用GetProperty()
+ GetField()
)
类似于:
static IQueryable<TTo> Select<TFrom, TTo>(
this IQueryable<TFrom> source,
params string[] members)
{
var p = Expression.Parameter(typeof(TFrom));
var body = Expression.MemberInit(
Expression.New(typeof(TTo)),
members.Select(member => Expression.Bind(
typeof(TTo).GetMember(member).Single(),
Expression.PropertyOrField(p, member))));
var lambda = Expression.Lambda<Func<TFrom, TTo>>(body, p);
return source.Select(lambda);
}
?
这会创建一个从 TFrom
到 TTo
的 IQueryable<T>
友好投影,尊重 members
的所有成员。
在您的示例中,它将是:
IQueryable<myClass> myClassIQ = qry.Select<T, myClass>(ListofSharedPropertyNames);
(在 members
参数的数组/列表之间进行调整以方便您使用 - 因为我们使用 Select
,它可以与任何一个一起使用)
我有一个包含 IQueryable<T>
的通用函数,其中每一行都包含一个具有一组属性的 class 实例。
我有另一个 class (MyClass),它与上面的 class T 具有一些相同的属性...即相同的名称和数据类型。
我还有一个字符串列表,其中包含两个 class 之间共享的 属性 名称。
我希望能够创建一个新的 IQueryable<myClass>
,其中 myClass 实例属性填充了原始 IQueryable<T>
这有意义吗?请让我知道我是否可以提供更多信息或使任何内容更清楚。
编辑 我会尝试添加一些代码来更好地说明。我知道这里有无数错误,包括添加到 IQueryable - 但这是为了说明:
IQueryable<T> qry = this.GetSomeDataIntoIQueryable();
// Just getting a list of the Shared Property Names between the two classes
List<string> sharedProprtyNames = new List<string>();
foreach (var item in ListofSharedPropertyNames)
{
sharedProprtyNames .Add(item.SharedPropertyName);
}
IQueryable<myClass> myClassIQ;
foreach(var classItem in qry)
{
myClass x = new myClass();
foreach(var sharedProperty in sharedProprtyNames )
{
myClass[sharedProperty] = classItem[sharedProperty];
}
myClassIQ.Add(myClass);
}
使用System.Linq.Dynamic.Core
您可以:
IQueryable<Table1> query1 = ...
var res = query.Select<SubTable1>("new(" + string.Join(",", new[] { "Col1", "Col2" }) + ")").ToArray();
其中query1
是您的查询,Table1
是您问题的T
,SubTable1
是MyClass
,"Col1", "Col2"
是必须选择的列。
你可以在不使用 System.Linq.Dynamic.Core
库和简单地构建表达式树的情况下做任何事情......但这很痛苦:-)
我对 Hans Passant 代码的变体:
public static IQueryable<TResult> Select<TSource, TResult>(this IQueryable<TSource> source, IEnumerable<string> columns)
{
// the x in x => ...
var par = Expression.Parameter(typeof(TSource), "x");
// "Bindings" (the Col1 = x.Col1 inside the x => new { Col1 = x.Col1 })
var binds = columns.Select(x => Expression.Bind((MemberInfo)typeof(TResult).GetProperty(x) ?? typeof(TResult).GetField(x), Expression.PropertyOrField(par, x)));
// new TResult
var new1 = Expression.New(typeof(TResult));
// new TResult { Bindings }
var mi = Expression.MemberInit(new1, binds);
// x => new TResult { Bindings }
var lambda = Expression.Lambda<Func<TSource, TResult>>(mi, par);
// Select(x => new TResult { Bindings })
return source.Select(lambda);
}
(几乎完全等同...唯一的区别是他使用GetMember()
而我使用GetProperty()
+ GetField()
)
类似于:
static IQueryable<TTo> Select<TFrom, TTo>(
this IQueryable<TFrom> source,
params string[] members)
{
var p = Expression.Parameter(typeof(TFrom));
var body = Expression.MemberInit(
Expression.New(typeof(TTo)),
members.Select(member => Expression.Bind(
typeof(TTo).GetMember(member).Single(),
Expression.PropertyOrField(p, member))));
var lambda = Expression.Lambda<Func<TFrom, TTo>>(body, p);
return source.Select(lambda);
}
?
这会创建一个从 TFrom
到 TTo
的 IQueryable<T>
友好投影,尊重 members
的所有成员。
在您的示例中,它将是:
IQueryable<myClass> myClassIQ = qry.Select<T, myClass>(ListofSharedPropertyNames);
(在 members
参数的数组/列表之间进行调整以方便您使用 - 因为我们使用 Select
,它可以与任何一个一起使用)