具有generics类属性的LINQ表达式

我想将一个IQueryable和一组id传递给一个方法,该方法根据这些id过滤IQueryable。

由于id可以是long或int,因此应该通常解决。

我想出了以下内容:

public static IEnumerable GetModified(IQueryable objects, TId[] ids) where T : class { return objects.Where(j => ids.Contains((TId)j.GetType().GetProperty("Id").GetValue(j))); } 

不幸的是我得到了例外:

LINQ to Entities无法识别方法’System.Object GetValue(System.Object)’方法,并且此方法无法转换为商店表达式。

exception是正常的,因为通过reflection获取属性显然无法转换为SQL。

我要尝试的一件事是创建一个公开接口,公开给定类型的Id属性:

 public interface HasId { T Id { get; set; } } 

现在,您可以将实体声明为实现HasId ,例如,如果Id的类型为int

下一步是修改你的方法,如下所示:

 public static IEnumerable GetModified (IQueryable objects, TId[] ids) where T : class, HasId { return objects.Where(j => ids.Contains(j.Id)); } 

请注意添加的通用限制: where T : class, HasId 。 这使您可以编写简化的j.Id ,它返回TId值,而不是求助于reflection。

请注意,我没有运行或测试此代码; 这只是我在看到你的问题时得到的一个想法,我希望它有所帮助。

更新:

这是另一种可能的解决方案,它不要求您以任何方式声明接口或更改类:

 public static IEnumerable GetModified (IQueryable objects, TId[] ids, Expression> idSelector) where T : class { return objects.Where(j => ids.Contains(idSelector(j))); } 

我在这里做的是添加Expression> idSelector参数,这个表达式可以返回给定T实例的Id

你会这样调用这个方法:

 var modified = GetModified(dbObjects, yourIdArray, entity => entity.Id); 

(只有第三个参数是新的;保留现在的其他参数)。

再次,我没有测试这是否有效甚至编译,因为我这里没有带VS的电脑:(。

entity framework不支持某些.NET方法,如GetValue()因为它不会转换为SQL(这是实际执行到IQueryable的代码。尝试在进行reflection之前调用ToList获取CLR对象:

 public static IEnumerable GetModified(IQueryable objects, TId[] ids) where T : class { return objects.ToList().Where(j => ids.Contains((TId)j.GetType().GetProperty("Id").GetValue(j))); }