如何使用Express.call方法为从DataTable获取数据创建(谓词)?[英] How to create (predicate) for fetching data from DataTable using Express.call method

本文是小编为大家收集整理的关于如何使用Express.call方法为从DataTable获取数据创建(谓词)?的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我在 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;
}

本文地址:https://www.itbaoku.cn/post/1556929.html

问题描述

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;
}