问题描述
我在 Home Controller 中有一个 DataTable,如下所示:
public DataTable GetTable() { DataTable table = new DataTable(); table.Columns.Add("Dosage", typeof(int)); table.Columns.Add("Drug", typeof(string)); table.Columns.Add("Patient", typeof(Info)); table.Columns.Add("Date", typeof(DateTime)); table.Rows.Add(25, "Indocin", new Info("India"), DateTime.Now); table.Rows.Add(50, "Enebrel", new Info("UK"), DateTime.Now); table.Rows.Add(10, "Hydralazine", new Info("Bhutan"), DateTime.Now); table.Rows.Add(21, "Combivent", new Info("India"), DateTime.Now); table.Rows.Add(100, "Dilantin", new Info("GreenLand"), DateTime.Now); return table; }
Info类如下
public class Info { public string Address { get; set; } public Info(string Add) { this.Address = Add; } }
现在,我想根据地址字段进行过滤操作,即 Patient.Address
这里,Patient 是 Info 类的对象
我需要形成条件,以便获取数据.
我正在使用 Express.call 方法形成条件
private static MethodCallExpression GetFieldCallExpression(Expression memExp, Type ColumnType, string ColumnName) { MethodInfo method = typeof(DataRowExtensions).GetMethods().Where(m => m.Name == "Field" && m.IsGenericMethod && m.GetParameters().Count() == 2 && m.GetParameters()[1].ParameterType == typeof(string)).FirstOrDefault(); var genericWrapper = method.MakeGenericMethod(new Type[] { ColumnType }); var toLowerMethodCall = Expression.Call( null, genericWrapper, memExp, Expression.Constant(ColumnName, ColumnName.GetType()) ); return toLowerMethodCall; }
这里,memExp - DataRow 的实例columnName - Patient.AddresscolumnType - 字符串
它得到的信息是,
"列'Patient.Address'不属于表."
我在哪里犯错了
推荐答案
DataRow 值访问器仅支持"顶级"列名(如示例中的"剂量"、"药物"、"患者"等).为了实现你的目标,你必须手动拆分路径并生成访问器.
例如,"Patient.Address"的示例访问器应该是 dr.Field<Info>("Patient").Address 或者换句话说:
var value1 = dr.Field<Info>("Patient"); var value2 = value1.Address; ... return value2;
这里是通用实现的:
private static Expression GetFieldValueExpression(Expression source, Type columnType, string memberPath) { var memberNames = memberPath.Split('.'); Expression value = Expression.Call( typeof(DataRowExtensions), "Field", new Type[] { columnType }, source, Expression.Constant(memberNames[0])); for (int i = 1; i < memberNames.Length; i++) value = Expression.PropertyOrField(value, memberNames[i]); return value; }
问题描述
I have a DataTable in Home Controller as follows:
public DataTable GetTable() { DataTable table = new DataTable(); table.Columns.Add("Dosage", typeof(int)); table.Columns.Add("Drug", typeof(string)); table.Columns.Add("Patient", typeof(Info)); table.Columns.Add("Date", typeof(DateTime)); table.Rows.Add(25, "Indocin", new Info("India"), DateTime.Now); table.Rows.Add(50, "Enebrel", new Info("UK"), DateTime.Now); table.Rows.Add(10, "Hydralazine", new Info("Bhutan"), DateTime.Now); table.Rows.Add(21, "Combivent", new Info("India"), DateTime.Now); table.Rows.Add(100, "Dilantin", new Info("GreenLand"), DateTime.Now); return table; }
Info class as follows
public class Info { public string Address { get; set; } public Info(string Add) { this.Address = Add; } }
Now, i want to do the filtering operation based on Address Field, i.e Patient.Address
Here, Patient is object of Info class
I need to form the condition, in order to fetch the data.
I am forming condition using Express.call method
private static MethodCallExpression GetFieldCallExpression(Expression memExp, Type ColumnType, string ColumnName) { MethodInfo method = typeof(DataRowExtensions).GetMethods().Where(m => m.Name == "Field" && m.IsGenericMethod && m.GetParameters().Count() == 2 && m.GetParameters()[1].ParameterType == typeof(string)).FirstOrDefault(); var genericWrapper = method.MakeGenericMethod(new Type[] { ColumnType }); var toLowerMethodCall = Expression.Call( null, genericWrapper, memExp, Expression.Constant(ColumnName, ColumnName.GetType()) ); return toLowerMethodCall; }
Here, memExp - instance of DataRow columnName - Patient.Address columnType - string
Predicate is formed as like this
It got the message that,
"Column 'Patient.Address' does not belong to table ."
Where did i commit my mistake
推荐答案
DataRow value accessors support only the "top level" column names (like "Dosage", "Drug", "Patient" etc. in your sample). In order to achieve your goal, you have to split the path and generate accessors manually.
For instance, the sample accessor for "Patient.Address" should be dr.Field<Info>("Patient").Address or in other words:
var value1 = dr.Field<Info>("Patient"); var value2 = value1.Address; ... return value2;
Here is the same implemented generically:
private static Expression GetFieldValueExpression(Expression source, Type columnType, string memberPath) { var memberNames = memberPath.Split('.'); Expression value = Expression.Call( typeof(DataRowExtensions), "Field", new Type[] { columnType }, source, Expression.Constant(memberNames[0])); for (int i = 1; i < memberNames.Length; i++) value = Expression.PropertyOrField(value, memberNames[i]); return value; }