我可以在非实体成员字段上创建 LINQ 到实体查询吗
我有一个实体类,我使用 partial class
语法对其进行了扩展,以具有一些派生属性。我想使用使用这些字段中的信息的 IQueryable
接口执行查询,但我当前收到一个异常,指出
指定的类型成员“Title”是 LINQ to Entities 不支持。 仅初始值设定项、实体成员和 实体导航属性是 支持。
这是相关的代码片段。您可以假设实体对象有一个名为 Id
的字符串成员。
public partial class MyEntityObject
{
public String Title { get { return MyStrings.ResourceManager.GetString(Id) ?? ""; } }
}
/**
* Throws exception trying to sort on the 'Title' field of a 'MyEntityObject'
*/
public IEnumerable<T> Query<T>(String fieldName, int low, int high)
{
// Get the ObjectContext<T> using a Repository pattern
var query = context.GetRepository<T>()
// Create an OrderBy clause based on the field by dynamically building an expression tree
// see http://stackoverflow.com/questions/4546463/help-with-linq-and-generics-using-getvalue-inside-a-query
PropertyInfo propertyInfo = typeof(T).GetProperty(fieldName);
ParameterExpression e = Expression.Parameter(typeof(T), "e");
MemberExpression mexpr = Expression.MakeMemberAccess(e, propertyInfo);
IQueryable<T> sortedQuery = query.OrderBy(Expression.Lambda<Func<T,Object>>(mexpr, e));
return sortedQuery.Skip(low).Take(high - low + 1).AsEnumerable();
}
作为最后的手段,我总是可以在 Skip
和 Take
之前执行 AsEnumerable()
,但这将涉及检索所有即使选择可以通过 SQL 完成,也可以从数据库中选择对象。
也许最好的替代方法是使用反射来检查对象属性是否具有 DataMemberAttribute,然后选择执行 query.OrderBy().Skip().Take().AsEnumerable() 还是query.AsEnumerable().OrderBy().Skip().Take()
?
I have an Entity class that I have extended using the partial class
syntax to have some derived properties. I would like to perform a query using the IQueryable<T>
interface that uses the information from these fields, but I currently get an exception that states
The specified type member 'Title' is
not supported in LINQ to Entities.
Only initializers, entity members, and
entity navigation properties are
supported.
Here are the relevant code snippets. You may assume that the Entity object has a String member named Id
.
public partial class MyEntityObject
{
public String Title { get { return MyStrings.ResourceManager.GetString(Id) ?? ""; } }
}
/**
* Throws exception trying to sort on the 'Title' field of a 'MyEntityObject'
*/
public IEnumerable<T> Query<T>(String fieldName, int low, int high)
{
// Get the ObjectContext<T> using a Repository pattern
var query = context.GetRepository<T>()
// Create an OrderBy clause based on the field by dynamically building an expression tree
// see http://stackoverflow.com/questions/4546463/help-with-linq-and-generics-using-getvalue-inside-a-query
PropertyInfo propertyInfo = typeof(T).GetProperty(fieldName);
ParameterExpression e = Expression.Parameter(typeof(T), "e");
MemberExpression mexpr = Expression.MakeMemberAccess(e, propertyInfo);
IQueryable<T> sortedQuery = query.OrderBy(Expression.Lambda<Func<T,Object>>(mexpr, e));
return sortedQuery.Skip(low).Take(high - low + 1).AsEnumerable();
}
As a last resort I can always do the AsEnumerable()
before the Skip
and Take
, but that will involve retrieving all of the objects from the database even if the selection can be done by SQL.
Perhaps the best alternative is to use reflection to check that the object property has a DataMemberAttribute
and then chose to do either query.OrderBy().Skip().Take().AsEnumerable()
or query.AsEnumerable().OrderBy().Skip().Take()
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
不,你不能,因为 linq-to-entities 查询只是转换为 SQL 的表达式树。要将树转换为 SQL,您将使用实体映射,并且由于
Title
不在您的映射中,因此会抛出异常。在
Skip
和Take
之前调用AsEnumerable
听起来像是非常糟糕的设计,因为它总是将整个数据表的内容传输到您的应用程序。这将非常慢,并且在大数据表的情况下也毫无用处。如果这是本地化问题,您的数据库必须包含本地化字符串才能使其有效。同时,如果您只需要对少数记录执行此操作,则可以加载所有记录。
No you can't because linq-to-entities query is just expression tree translated to SQL. To translate the tree to SQL your entity mapping is used and because
Title
is not in your mapping it will throw exception.Calling
AsEnumerable
beforeSkip
andTake
sounds like very bad design because it will always transfer content of whole data table to your application. This will be very slow and in case of big data tables also useless.If this is a problem of localization your database must contain localized strings to make this effective. In the same time if you need to do this only with few records you can load all of them.