2014-02-09 93 views
2

获取数据的表达式查询的动态创建我想创建Expression类型的查询会从实体框架的实体的一些列。从实体框架

假设我们有两个类是这样的:

public class Parent 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public Child MyChild { get; set; } 
} 

public class Child 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

而且我们有ParentIQueryable列表:

var q = new List<Parent>() 
{ 
    new Parent {Id = 1, Name = "a", Number = 1, MyChild=new Child{Id=11,Name="Child_a",Number=2}}, 
    new Parent {Id = 2, Name = "b", Number = 1, MyChild=new Child{Id=22,Name="Child_b",Number=2}}, 
    new Parent {Id = 3, Name = "c", Number = 1, MyChild=new Child{Id=33,Name="Child_c",Number=2}}, 
}.AsQueryable(); 

我希望该用户决定他们得到的q这些属性的列表。例如,用户确定他需要Parent.NameParent.MyChils.Name。所以,我应该给用户这样的匿名类型的列表:

{"a","Child_a"} 
{"b","Child_b"} 
{"c","Child_c"} 

如果Parent实体不含有任何外键属性(在这个例子中MyChild属性)它是那么容易创造一个表达的属性,动态地获取Parent的一些属性。我有得到的Person某些属性没有它MyChild属性的代码:

var columns = new List<string> { "Id", "Name" }; 
var xParam = Expression.Parameter(typeof(Parent), "x"); 
var sourceProperties = columns.ToDictionary(name => name, 
    name => q.ElementType.GetProperty(name)); 
var dynamicType = LinqRuntimeTypeBuilder.GetDynamicType(sourceProperties.Values); 
var bindings = 
    dynamicType.GetFields() 
     .Select(p => Expression.Bind(p, Expression.Property(xParam, sourceProperties[p.Name]))) 
     .OfType<MemberBinding>(); 
var newExpr = Expression.New(dynamicType.GetConstructor(Type.EmptyTypes)); 
Expression selector = Expression.Lambda(Expression.MemberInit(
    Expression.New(dynamicType.GetConstructor(Type.EmptyTypes)), bindings), xParam); 
var body = Expression.MemberInit(newExpr, bindings); 
var lambda = Expression.Lambda<Func<Parent, dynamic>>(body, xParam); 
var t = q.Select(lambda); 

(使用2种方法在这里:)

public static Type GetDynamicType2(Dictionary<string, Type> fields) 
{ 
    if (null == fields) 
     throw new ArgumentNullException("fields"); 
    if (0 == fields.Count) 
     throw new ArgumentOutOfRangeException("fields", "fields must have at least 1 field definition"); 
    try 
    { 
     Monitor.Enter(builtTypes); 
     string className = "MyDynamicType"; 
     if (builtTypes.ContainsKey(className)) 
      return builtTypes[className]; 
     TypeBuilder typeBuilder = moduleBuilder.DefineType(className, 
      TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Serializable); 
     foreach (var field in fields) 
      typeBuilder.DefineField(field.Key, field.Value, FieldAttributes.Public); 
     builtTypes[className] = typeBuilder.CreateType(); 
     return builtTypes[className]; 
    } 
    catch (Exception ex) 
    { 
    } 
    finally 
    { 
     Monitor.Exit(builtTypes); 
    } 

    return null; 
} 

public static Type GetDynamicType(IEnumerable<PropertyInfo> fields) 
{ 
    return GetDynamicType(fields.ToDictionary(f => f.Name, f => f.PropertyType)); 
} 

但我仍不能得到MyChild属性的内部属性的Parent

如何做到这一点?

回答

1

因为没有人回答我的问题,我尝试了许多不同的方法来解决这个问题,结果问题就解决了使用递归创建Expression。 对于(在这个问题就像MyChildClass类型的每个属性,我们最创建一个Expression。的Expressions创造最是递归的是这样的:在保持内部属性的路径是空的

private Expression BuildExpression(Expression parentExpression, 
     Type parentPropertyType, string pathOfChildProperty) 
    { 
     string remainPathOfChild; 
     var childPropertyName = 
       GetFirstPropertyNameFromPathAndRemainPath(pathOfChildProperty, out remainPathOfChild); 
     if (string.IsNullOrEmpty(childPropertyName)) return parentExpression; 
     var childPropInfo = parentPropertyType.GetProperty(childPropertyName); 
     var childExpression = Expression.Property(parentExpression, childPropInfo); 
     return !string.IsNullOrEmpty(remainPathOfChild) 
      ? BuildExpressionForInternalProperty(childExpression, childPropInfo.PropertyType, remainPathOfChild) 
      : childExpression; 
    } 
    private string GetFirstPropertyNameFromPathAndRemainPath(string path, out string remainPath) 
    { 
     if (string.IsNullOrEmpty(path)) 
     { 
      remainPath = null; 
      return null; 
     } 
     var indexOfDot = path.IndexOf('.'); 
     if (indexOfDot < 0) 
     { 
      remainPath = null; 
      return path; 
     } 
     remainPath = path.Substring(indexOfDot + 1); 
     return path.Substring(0, indexOfDot); 
    } 
    } 

递归调用将停止。 在最高水平此方法的调用是这样的:

var inputParameter = Expression.Parameter(typeof(GrandParent), "x"); 
var expChildProperty = 
    BuildExpression(inputParameter,typeof(Parent),"Parent.MyChils.Name"); 

最后导致对其上述问题表达在调试视图(($x.Parent).MyChils).Name