繁体   English   中英

如何用反射重写此LINQ查询

[英]How can I rewrite this LINQ query with reflection

因此,我已使用反射编写了此LINQ查询,后来发现它不受支持。 从此代码中获得相同功能的最佳方法是什么?

List<Profile> profilesFromUUID = await MobileService.GetTable<Profile>().Where(p => typeof(Profile)
.GetProperty(handler.Name + "UUID").GetValue(p) == obj.uuid).ToListAsync();

仅比较所有属性名称如何? 根据定义UUID 不会有冲突呢。 由于Profile只是一个数据类,因此UUID的属性号是固定的。

List<Profile> profilesFromUUID = await MobileService.GetTable<Profile>()
    .Where(p => 
        p.A_UUID == obj.uuid || 
        p.B_UUID == obj.uuid ||
        p.C_UUID == obj.uuid)
    .ToListAsync();

或为Profile添加一个方法(扩展方法),例如:

public static Guid GetUUIDByTableName(this Profile value, string tableName)
{
    switch (tableName)
    {
        case "A_": return value.A_UUID;
        case "B_": return value.B_UUID;
        default: return Guid.Empty;
    }
}


List<Profile> profilesFromUUID = await MobileService.GetTable<Profile>()
    .Where(p => p.GetUUIDByTableName(handler.Name) == obj.uuid)
    .ToListAsync();

使用反射来创建查询,而不是在查询中。 考虑:

public static IQueryable<Profile> Filter(
  this IQueryable<Profile> source, string name, Guid uuid)
{
  // .<name>UUID
  var property = typeof(Profile).GetProperty(name + "UUID");

  // p
  var parExp = Expression.Parameter(typeof(Profile));

  // p.<name>UUID
  var methodExp = Expression.Property(parExp, property);     

  // uuid
  var constExp = Expression.Constant(uuid, typeof(Guid));    

  // p.<name>UUID == uuid
  var binExp = Expression.Equal(methodExp, constExp);                  

  // p => p.<name>UUID == uuid
  var lambda = Expression.Lambda<Func<Profile, bool>>(binExp, parExp);

  // source.Where(p => p.<name>UUID == uuid)
  return source.Where(lambda);
}

这将首先构建表达式(因此,如果name为“ Test”,它将创建与p => p.TestUUID == uuid相对应的表达式,然后在对Where的调用中使用该表达式。

因为此步骤是首先完成的,而不是在表达式本身内部完成的,所以查询引擎无需尝试将typeofGetProperty()转换为SQL(当然不能这样做)。

所以:

var filtered = MobileService.GetTable<Profile>().Filter(handler.Name, obj.uuid);

返回IQueryable<Profile>用适当的Where附接。 所以:

var profilesFromUUID = await MobileService.GetTable<Profile>().Filter(handler.Name, obj.uuid).ToListAsync();

总体而言,将首先使用反射来构建查询,然后应用查询,然后异步从中生成一个列表,然后等待其结果。

值得注意的是,由于Filter()将接受任何IQueryable<Profile>因此它们可以链接或联合。 所以:

MobileService.GetTable<Profile>().Filter("A", uuid0).Filter("B", uuid1);

等效于:

from p in MobileService.GetTable<Profile>() where p.AUUID = uuid0 && p.BUUID == uuid1

和:

MobileService.GetTable<Profile>().Filter("A", uuid0).Union(
  MobileService.GetTable<Profile>().Filter("B", uuid1))

等效于:

from p in MobileService.GetTable<Profile>() where p.AUUID = uuid0 || p.BUUID == uuid1

更通用的版本是:

public static IQueryable<TSource> FilterByNamedProperty<TSource, TValue>(this IQueryable<TSource> source, string propertyName, TValue value)
{
  var property = typeof(TSource).GetProperty(propertyName);
  var parExp = Expression.Parameter(typeof(TSource));
  var methodExp = Expression.Property(parExp, property);
  var constExp = Expression.Constant(value, typeof(TValue));
  var binExp = Expression.Equal(methodExp, constExp);
  var lambda = Expression.Lambda<Func<TSource, bool>>(binExp, parExp);
  return source.Where(lambda);
}

然后,当您必须在调用代码中执行+ "UUID"时,您可以使用IQueryable<>任何元素类型的任何IQueryable<>进行类似的查询。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM