Разбор дерева выражений - PullRequest
       6

Разбор дерева выражений

0 голосов
/ 21 сентября 2018

Я хочу построить Dapper строку, используя выражение LINQ в качестве аргумента метода.Я нашел в MS Docs пример синтаксического анализа и интегрировал его в мой код:

public static List<Notification> GetNotifs(Expression<Func<Notification, bool>> p)
        {
            using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
            {
                string sqlQ = "SELECT * FROM Notifications WHERE ";
                ParameterExpression param = p.Parameters[0];
                BinaryExpression operation = (BinaryExpression)p.Body;
                ParameterExpression left = (ParameterExpression)operation.Left;
                for (int i = 0; i < left.Name.Length; i++) { if (i <= param.Name.Length) { } else { sqlQ += left.Name[i]; } }
                ConstantExpression right = (ConstantExpression)operation.Right;
                if (operation.NodeType.ToString() == "LessThan") sqlQ += " <";
                else if (operation.NodeType.ToString() == "GreaterThan") sqlQ += " >";
                else if (operation.NodeType.ToString() == "LessThanOrEqual") sqlQ += " <=";
                else if (operation.NodeType.ToString() == "GreaterThanOrEqual") sqlQ += " >=";
                else if (operation.NodeType.ToString() == "Equal") sqlQ += " =";
                else if (operation.NodeType.ToString() == "NotEqual") sqlQ += " !=";
                sqlQ += " " + right.Value;
                return connection.Query<Notification>(sqlQ).ToList();
            }
        }

Но, к сожалению, он дает InvalidCastException при

ParameterExpression left = (ParameterExpression)operation.Left;

Вызов этого методаэто как:

DRepository.GetNotifs(uid => uid.U_Id == id)

Не могли бы вы помочь мне выяснить, где я не прав?

1 Ответ

0 голосов
/ 21 сентября 2018

В следующем примере генерируется SQL SELECT * FROM Notifications WHERE U_Id = 1:

[Test]
public void DapperExpression()
{
    // Arrange
    var id = 1;

    // Act
    var list = GetNotifs(uid => uid.U_Id == id);

    // Assert 
    Assert.IsNotEmpty(list);
}

public static List<Notification> GetNotifs(Expression<Func<Notification, bool>> p)
{
    using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
    {
        string sqlQ = "SELECT * FROM Notifications WHERE ";
        ParameterExpression param = p.Parameters[0];
        BinaryExpression operation = (BinaryExpression)p.Body;
        var t = operation.Left.GetType();
        MemberExpression left = (MemberExpression)operation.Left;
        sqlQ += left.Member.Name;
        MemberExpression right = (MemberExpression)operation.Right;
        ConstantExpression cnst = (ConstantExpression) right.Expression;
        var field = cnst.Type.GetFields().Single();
        var val = field.GetValue(cnst.Value);

        if (operation.NodeType.ToString() == "LessThan") sqlQ += " <";
        else if (operation.NodeType.ToString() == "GreaterThan") sqlQ += " >";
        else if (operation.NodeType.ToString() == "LessThanOrEqual") sqlQ += " <=";
        else if (operation.NodeType.ToString() == "GreaterThanOrEqual") sqlQ += " >=";
        else if (operation.NodeType.ToString() == "Equal") sqlQ += " =";
        else if (operation.NodeType.ToString() == "NotEqual") sqlQ += " !=";
        sqlQ += " " + val;

        return connection.Query<Notification>(sqlQ).ToList();
    }
}

Обратите внимание, что он будет работать в случае int.Вы должны добавить некоторую типозависимую логику, чтобы добавить квоты для string или Guid, например.Вы можете получить этот тип из переменной field.Надеюсь, это поможет.

...