再一次,我遇到了一个问题,这次是LINQ Expression构建器,这次我甚至在努力找到它无法正常工作的原因。我有一个数据库优先EF项目,有很多表。对于这种特殊情况,我必须使用其中的两个 - DocHead和Contragent。 MyService.metadata.cs如下所示:
[MetadataTypeAttribute(typeof(DocHead.DocHeadMetadata))]
public partial class DocHead
{
// This class allows you to attach custom attributes to properties
// of the DocHead class.
//
// For example, the following marks the Xyz property as a
// required property and specifies the format for valid values:
// [Required]
// [RegularExpression("[A-Z][A-Za-z0-9]*")]
// [StringLength(32)]
// public string Xyz { get; set; }
internal sealed class DocHeadMetadata
{
// Metadata classes are not meant to be instantiated.
private DocHeadMetadata()
{
}
public string doc_Code { get; set; }
public string doc_Name { get; set; }
public string doc_ContrCode { get; set; }
//...
[Include]
public Contragent Contragent { get; set; }
}
}
[MetadataTypeAttribute(typeof(Contragent.ContragentMetadata))]
public partial class Contragent
{
// This class allows you to attach custom attributes to properties
// of the Contragent class.
//
// For example, the following marks the Xyz property as a
// required property and specifies the format for valid values:
// [Required]
// [RegularExpression("[A-Z][A-Za-z0-9]*")]
// [StringLength(32)]
// public string Xyz { get; set; }
internal sealed class ContragentMetadata
{
// Metadata classes are not meant to be instantiated.
private ContragentMetadata()
{
}
public string Code { get; set; }
public string Name { get; set; }
//...
我带了一些像这样的docHeads:
IQueryable<DocHead> docHeads = new MyEntities().DocHead;
然后我尝试按照这样排序:
docHeads = docHeads.OrderByDescending(x => x.Contragent.Name);
这一切都像我想要的那样工作。我将这些docHeads按加入的Contragent的名称排序。我的问题是我必须按字段对它们进行排序,作为字符串参数给出。我需要能够写出这样的东西:
string field = "Contragent.Name";
string linq = "docHeads = docHeads.OrderByDescending(x => x." + field + ")";
IQueryable<DocHead> result = TheBestLinqLibraryInTheWorld.PrepareLinqQueryable(linq);
不幸的是,TheBestLinqLibraryInTheWorld不存在(暂时)。所以,我已经设置了一种方法作为解决方法。
public static IQueryable<T> OrderByField<T>(this IQueryable<T> q, string SortField, bool Ascending)
{
var param = Expression.Parameter(typeof(T), "x");
var prop = Expression.Property(param, SortField); // normally returns x.sortField
var exp = Expression.Lambda(prop, param); // normally returns x => x.sortField
string method = Ascending ? "OrderBy" : "OrderByDescending";
Type[] types = new Type[] { q.ElementType, exp.Body.Type };
var mce = Expression.Call(typeof(Queryable), method, types, q.Expression, exp); // normally returns sth similar to q.OrderBy(x => x.sortField)
return q.Provider.CreateQuery<T>(mce);
}
通常......是的,当谈到DocHead类的自有属性时 - 那些以doc_为前缀的属性。当我这样称呼这个方法时,灾难来袭了:
docHeads = docHeads.OrderByField<DocHead>("Contragent.Name", true); // true - let it be Ascending order
更具体地说,标题中的异常抛出OrderByField()方法的第2行:
var prop = Expression.Property(param, SortField);
在My.edmx(模型)中,DocHead和Contragent表已经为我设置了关系,如下所示:0..1到*。
再一次,我完全没有问题写“静态”查询。通过OrderByField()方法创建“动态”方法没有问题,但仅限于DocHead类的属性。当我试图通过加入的Contragent类的道具订购时 - 灾难来袭。任何帮助都会非常有用,谢谢!
答案 0 :(得分:1)
问题是Expression.Property
方法不支持嵌套属性。它完全按照它所说的 - 创建表达式,表示由UITableView
参数表示的对象的propertyName
参数表示的属性。
幸运的是,它很容易扩展。您可以在需要创建嵌套属性访问表达式时随时使用以下简单Split
/ Aggregate
技巧:
expression