Reputation: 17388
I am trying to work with this. I have written a unit test as a starter for ten like so:
[Fact]
public void TestOredGuids()
{
// Arrange
const string expectedSql = "SELECT * FROM Products WHERE SomeExternalForeignKey = @SomeExternalForeignKey OR Name = SomeExternalForeignKey = @SomeExternalForeignKey";
// Act
var result = DynamicQuery.GetDynamicQuery<Product>("Products", p => p.SomeExternalForeignKey == new Guid("28D3BCFB-9472-4141-BD88-BE5E7E1230F0") || p.SomeExternalForeignKey == new Guid("0F0DBA45-F842-4E46-9ED4-F50B5BCF0509"));
// Assert
}
internal class Product
{
public string Name { get; set; }
public decimal Price { get; set; }
public DateTime ExpiryDate { get; set; }
public int CategoryId { get; set; }
public Guid SomeExternalForeignKey { get; set; }
}
Unfortunately, I am always getting:
Additional information: 'System.Linq.Expressions.NewExpression' does not contain a definition for 'Value'
in the WalkTree method. Am I using GetDynamicQuery wrongly?
If there are any other implementation of dynamic sql mappers like this for dapper, I would appreciate any pointers. Thanks!
Upvotes: 0
Views: 1320
Reputation: 205539
From what I see in the source code of the component you are trying to use, it expects the right operand of the expression to be a ConstantExpression (although for some unknown reason the author is using dynamic
and expects a Value
property), so to make it work, modify you code as follows
var someExternalForeignKey1 = new Guid("28D3BCFB-9472-4141-BD88-BE5E7E1230F0");
var someExternalForeignKey2 = new Guid("0F0DBA45-F842-4E46-9ED4-F50B5BCF0509");
var result = DynamicQuery.GetDynamicQuery<Product>("Products", p => p.SomeExternalForeignKey == someExternalForeignKey1 || p.SomeExternalForeignKey == someExternalForeignKey2);
Update: It turns out that the above also doesn't work, because of course it produces a closure which is not ConstantExpression
. To make it work (as well as your original code), here are the required modifications of the DynamicQuery
class
private static void WalkTree(BinaryExpression body, ExpressionType linkingType,
ref List<QueryParameter> queryProperties)
{
if (body.NodeType != ExpressionType.AndAlso && body.NodeType != ExpressionType.OrElse)
{
string propertyName = GetPropertyName(body);
var propertyValue = GetPropertyValue(body.Right);
string opr = GetOperator(body.NodeType);
string link = GetOperator(linkingType);
queryProperties.Add(new QueryParameter(link, propertyName, propertyValue, opr));
}
else
{
WalkTree((BinaryExpression)body.Left, body.NodeType, ref queryProperties);
WalkTree((BinaryExpression)body.Right, body.NodeType, ref queryProperties);
}
}
private static object GetPropertyValue(Expression source)
{
var constantExpression = source as ConstantExpression;
if (constantExpression != null)
return constantExpression.Value;
var evalExpr = Expression.Lambda<Func<object>>(Expression.Convert(source, typeof(object)));
var evalFunc = evalExpr.Compile();
var value = evalFunc();
return value;
}
But note that the whole class (as the author states) is just an example, and for instance maps just one parameter (thus one value) per property, so in order to make it really useful, the GetDynamicQuery
method needs additional work. You might try this one instead. Hope that helps.
Upvotes: 1