How to convert string to System.Linq.Expressions.Expression - c#

I have a grid which shows records from a table. On this grid I am using customized pagination and sorting, so I need to use customized column filtering as well.
var expression = ExpressionBuilder.Expression<EventModel>(request.Filters);
The above code snippet gets filter condition from Kendo Grid in the controller of type System.Linq.Expressions.Expression<Func<EventModel,bool>> expression,
and am converting it to string, and passing it to DAL code as shown below,
string filterExpression = ExpressionBuilder.Expression<EventModel>(request.Filters).ToString();
List<EventModel> eventModelList = new List<EventModel>();
eventModelList = eventComponent.GetEventData(request.PageSize, request.Page, searchstring, sortDirection, sortColumnName, filterExpression, ref recCount);
In the DAL I need to convert filterExpression from string to System.Linq.Expressions.Expression<Func<EventModel,bool>>
var res = eventInfo.AsQueryable().Where(filterExpression);//Gets error here
lstEventInfo = lstEventInfo.AsQueryable().Where(res);
Am getting an error can not convert from string to System.Linq.Expressions.Expression>'.
So could anyone tell me how could I convert a string to System.Linq.Expressions.Expression<System.Func<ModelClass,bool>> type in C#.

Here is a simple example how to create where dynamically.
public class Mock
{
public int Id { get; set; }
public int ForeignId { get; set; }
public decimal Total { get; set; }
}
class Program
{
static void Main(string[] args)
{
var list = new List<Mock>()
{
new Mock{
Id = 1,
ForeignId = 1,
Total = 100,
},
};
var query = list.AsQueryable();
// t
var parameter = Expression.Parameter(typeof(Mock), "t");
// t.Total
var propertyExpression = Expression.PropertyOrField(parameter, "Total");
// 100.00M
var constant = Expression.Constant(100M, typeof(decimal));
// t.Total == 100.00M
var equalExpression = Expression.Equal(propertyExpression, constant);
// t => t.Total == 100.00M
var lambda = Expression.Lambda(equalExpression, parameter);
// calls where.
var whereExpression = Expression.Call(typeof(Queryable), "Where", new[] { query.ElementType }, query.Expression, lambda);
// add where to query.
query = query.Provider.CreateQuery(whereExpression) as IQueryable<Mock>;
Console.ReadKey();
}
}
But You can use this
https://github.com/PoweredSoft/DynamicLinq
here is the Nuget package
https://www.nuget.org/packages/PoweredSoft.DynamicLinq/
There is a litle sample here how to do simple web filtering
https://github.com/PoweredSoft/DynamicLinq#how-it-can-be-used-in-a-web-api
You could adapt it to fit your filter expression model.
[HttpGet][Route("FindClients")]
public IHttpActionResult FindClients(string filterField = null, string filterValue = null,
string sortProperty = "Id", int? page = null, int pageSize = 50)
{
var ctx = new MyDbContext();
var query = ctx.Clients.AsQueryable();
if (!string.IsNullOrEmpty(filterField) && !string.IsNullOrEmpty(filterValue))
query = query.Query(t => t.Contains(filterField, filterValue)).OrderBy(sortProperty);
// count.
var clientCount = query.Count();
int? pages = null;
if (page.HasValue && pageSize > 0)
{
if (clientCount == 0)
pages = 0;
else
pages = clientCount / pageSize + (clientCount % pageSize != 0 ? 1 : 0);
}
if (page.HasValue)
query = query.Skip((page.Value-1) * pageSize).Take(pageSize);
var clients = query.ToList();
return Ok(new
{
total = clientCount,
pages = pages,
data = clients
});
}
An alternative is to use DynamicLinq
https://weblogs.asp.net/scottgu/dynamic-linq-part-1-using-the-linq-dynamic-query-library

I wrote this code snippet for converting from string to Expression.
public List<Product> Get(string filter = null)
{
var p = Expression.Parameter(typeof(Product), "x");
var e = (Expression)DynamicExpressionParser.ParseLambda(new[] { p }, null, filter);
var typedExpression = (Expression<Func<Product, bool>>)e;
var res = _productDal.GetList(typedExpression);
return res;
}
I used System.Linq.Dynamic.Core namespace for Asp.Net Core. You can use System.Linq.Dynamic namespace for Asp.Net.
If you use classic Asp.Net instead of Asp.Net Core, you should write
var e = (Expression)DynamicExpression.ParseLambda(new[] { p }, null, filter); instead of
var e = (Expression)DynamicExpressionParser.ParseLambda(new[] { p }, null, filter);
And your string parameter (which is named as a filter) should be like "(x.ProductID > 10)"
If your string parameter is different, you can use following code snippet to convert from expression to string for getting same string parameter into Get method.
public static string Select(this Grid _grid, Expression<Func<Product, bool>> filter = null)
{
//filter = {x => (x.ProductID > 1)}
BinaryExpression be = filter.Body as BinaryExpression;
//be = {(x.ProductID > 1)}
return be.ToString();
}

Related

Unable to cast object of type 'System.Linq.Expressions.ConstantExpression' to type 'Microsoft.EntityFrameworkCore.Query.QueryRootExpression'

This is the function i am trying to write unit test for. On of the methods happens to use FromSqlRaw() to fetch the data from SQL Server via a stored procedure.
public async Task<IQueryable<LoadDetail>> GlobalSearchMobileByLocation(IQueryable<LoadDetail> loadDetails, List<LocationCoordinates> origin, List<LocationCoordinates> destination, int originRadius, int destinationRadius)
{
// Getting Cities within Radius
Stopwatch getCitiesStopWatch = new Stopwatch();
getCitiesStopWatch.Start();
var rawsql = new StringBuilder();
rawsql.Append(Constant.SqlBaseQueryLoadDetail);
if (origin != null && originRadius != 0)
{
rawsql.Append(" ( ");
foreach (var locationCoordinates in origin)
{
rawsql.Append(BuildSearchMobileQuery(locationCoordinates, originRadius, Constant.OriginLatitudeField, Constant.OriginLongitudeField));
}
rawsql = new StringBuilder(rawsql.ToString().Substring(0, rawsql.ToString().LastIndexOf("or") - 1));
rawsql.Append(") and ");
}
if (destination != null && destinationRadius != 0)
{
rawsql.Append(" ( ");
foreach (var locationCoordinates in destination)
{
rawsql.Append(BuildSearchMobileQuery(locationCoordinates, destinationRadius, Constant.DestinationLatitudeField, Constant.DestinationLongitudeField));
}
rawsql = new StringBuilder(rawsql.ToString().Substring(0, rawsql.ToString().LastIndexOf("or") - 1));
rawsql.Append(") and ");
}
rawsql.Append(Constant.TrueStatementSql);
var query = rawsql.ToString();
try
{
loadDetails = _readContext.LoadDetails.FromSqlRaw(rawsql.ToString()).AsNoTracking().AsQueryable();
}
catch (Exception ex )
{
throw;
}
getCitiesStopWatch.Stop();
_logger.LogInformation("Time taken to get cities based on radius(ms) : " + getCitiesStopWatch.ElapsedMilliseconds.ToString());
return await Task.FromResult(loadDetails);
}
I wrote this x unit test case for the function but it is throwing error.
public void Should_return_LoadWithinTheDHRadius_OriginIsPassedOnly()
{
// Arrange
var fixture = new Fixture();
var loadDetail = Enumerable.Empty<LoadDetail>().AsQueryable();
var loadDetailList = fixture.Create<LoadDetail>();
loadDetailList.PickupDateTime = DateTime.Now.Date;
loadDetailList.DeliveryDateTime = DateTime.Now.Date;
loadDetailList.OriginZipCode = Constant.Zip;
loadDetailList.DestinationZipCode = Constant.Zip;
loadDetailList.LoadId = Guid.Parse("8563c24c-c402-4960-b172-d379543f0096");
loadDetailList.OriginCityName = Constant.OriginCityName;
loadDetailList.OriginStateName = Constant.OriginStateName;
loadDetailList.DestinationCityName = Constant.DestinationCityName;
loadDetailList.DestinationStateName = Constant.DestinationStateName;
loadDetailList.OriginLongitude = 34.45666;
loadDetailList.OriginLatitude = 34.45666;
loadDetailList.DestinationLongitude = 34.45666;
loadDetailList.DestinationLatitude = 34.45666;
loadDetailList.SourceLoadId = 123456;
var loadDetailMock = new List<LoadDetail>() { loadDetailList }.AsQueryable();
//this.readContext<IQueryable<LoadDetails>>.Setup(x => x.LoadDetails).Returns(() => loadDetailMock.Object);
//readContext.Setup(x => x.LoadDetails(It.IsAny<string>(), It.IsAny<object[]>())).Returns(tableContent);
// this.readContext.Setup(x => x.LoadDetails)..Returns(() => loadDetailMock.Object);
var dbset = new Mock<DbSet<LoadDetail>>();
dbset.As<IQueryable<LoadDetail>>().Setup(x => x.Provider).Returns(loadDetailMock.Provider);
dbset.As<IQueryable<LoadDetail>>().Setup(x => x.Expression).Returns(loadDetailMock.Expression);
dbset.As<IQueryable<LoadDetail>>().Setup(x => x.ElementType).Returns(loadDetailMock.ElementType);
dbset.As<IQueryable<LoadDetail>>().Setup(x => x.GetEnumerator()).Returns(loadDetailMock.GetEnumerator());
this.readContext.Setup(x => x.)
var originCoordinate = new List<LocationCoordinates>() { new LocationCoordinates() { Radius = 75, Latitude = "34.45666", Longitude = "34.45666" } };
var destinationCoordinate = new List<LocationCoordinates>() { new LocationCoordinates() { Radius = 75, Latitude = "34.45666", Longitude = "34.45666" } };
var searchByRadius = GetSearchByRadiusObject();
// Act
var result = searchByRadius.GlobalSearchMobileByLocation(loadDetail, originCoordinate, destinationCoordinate, 75, 75);
// Assert to be written
}
The exception it throwing :
Unable to cast object of type 'System.Linq.Expressions.ConstantExpression' to type 'Microsoft.EntityFrameworkCore.Query.QueryRootExpression'.
At line loadDetails = _readContext.LoadDetails.FromSqlRaw(rawsql.ToString()).AsNoTracking().AsQueryable();
Please help me out.
Stack Trace :
at System.Runtime.CompilerServices.CastHelpers.ChkCast_Helper(Void* toTypeHnd, Object obj)
at Microsoft.EntityFrameworkCore.RelationalQueryableExtensions.GenerateFromSqlQueryRoot(IQueryable source, String sql, Object[] arguments, String memberName)
at Microsoft.EntityFrameworkCore.RelationalQueryableExtensions.FromSqlRaw[TEntity](DbSet`1 source, String sql, Object[] parameters)
at NTG.FH.LoadBoard.Service.Common.SearchByRadius.<GlobalSearchMobileByLocation>d__4.MoveNext() in C:\loadboard\src\NTG.FH.LoadBoard.Service\Common\SearchByRadius.cs:line 125

Lambda Expression for dynamic Object

I am trying to build a Lambda Expression for a table that has been created at run time.
The Expression is build fine but when I call Compile() method I get this error
"ParameterExpression of type 'cseval.Item' cannot be used for delegate parameter of type 'System.Object'"
this is my function
public Func<dynamic, Boolean> GetWhereExp(List<WhereCondition> SearchFieldList, dynamic item)
{
ParameterExpression pe = Expression.Parameter(item.GetType(), "c");
Expression combined = null;
if (SearchFieldList != null)
{
foreach (WhereCondition fieldItem in SearchFieldList)
{
//Expression for accessing Fields name property
Expression columnNameProperty = Expression.Property(pe, fieldItem.ColumName);
//the name constant to match
Expression columnValue = Expression.Constant(fieldItem.Value);
//the first expression: PatientantLastName = ?
Expression e1 = Expression.Equal(columnNameProperty, columnValue);
if (combined == null)
{
combined = e;
}
else
{
combined = Expression.And(combined, e);
}
}
}
var result = Expression.Lambda<Func<dynamic, bool>>(combined, pe);
return result.Compile();
}
I've changed dynamic to generics, this code works for me:
public Func<T, Boolean> GetWhereExp<T>(List<WhereCondition> SearchFieldList, T item)
{
var pe = Expression.Parameter(item.GetType(), "c");
Expression combined = null;
if (SearchFieldList != null)
{
foreach (var fieldItem in SearchFieldList)
{
var columnNameProperty = Expression.Property(pe, fieldItem.ColumName);
var columnValue = Expression.Constant(fieldItem.Value);
var e1 = Expression.Equal(columnNameProperty, columnValue);
combined = combined == null ? e1 : Expression.And(combined, e1);
}
}
var result = Expression.Lambda<Func<T, bool>>(combined, pe);
return result.Compile();
}
Small remark: your method returns function, not an expression, so the name 'GetWhereExp' is slightly incorrect. If you want to return function, imho, it's better to use reflection.
UPD: I use this code to test:
var expressions = new List<WhereCondition>
{
new WhereCondition("Column1", "xxx"),
new WhereCondition("Column2", "yyy"),
};
var item = new
{
Column1 = "xxx",
Column2 = "yyy"
};
var func = LinqExpr.GetWhereExp(expressions, (dynamic)item);
Console.WriteLine(new[] {item}.Count(a => func(a)));

Lambda to SQL Translation

So I am having fun with myself and C#, by creating a nice Data Access Layer.
I have the following method that translates a simple expression to a SQL where clause, but it only works with the following
var people = DataAccessLayer.SelectAllPeople(x => x.Name == "Donald");
//Do some changes to the list
people[0].Surname = "Jansen"
var m = p.BuildUpdateQuerry(people[0], x => x.PersonID == 1);
I get the following result
UPDATE People SET Name='Donald',Surname='Jansen' WHERE (PersonID = 1)
But now If I do the following
var m = p.BuildUpdateQuerry(people[0], x => x.PersonID == people[0].PersonID);
I get the following Result
UPDATE People SET Name='Donald',Surname='Jansen' WHERE (PersonID = value(ReflectionExampleByDonaldJansen.Program+<>c__DisplayClass0).people.get_Item(0).PersonID)
My method I am using to Convert the Lambda to String is
public static string GetWhereClause<T>(Expression<Func<T, bool>> expression)
{
var name = expression.Parameters[0].ToString();
var body = expression.Body.ToString().Replace("\"", "'");
body = body.Replace("OrElse", "OR");
body = body.Replace("AndAlso", "AND");
body = body.Replace("==", "=");
body = body.Replace("!=", "<>");
body = body.Replace(string.Format("{0}.", name), "");
return body;
}
So far this is very basic and real fun to do, but I have no Idea how to overcome this XDXD, any Suggestions or Codes ?
I managed to solve it myself, hehehe here is what I did, not finnished yet but maybe someone else might find it usefull
public static string GetWhereClause<T>(Expression<Func<T, bool>> expression)
{
return GetValueAsString(expression.Body);
}
public static string GetValueAsString(Expression expression)
{
var value = "";
var equalty = "";
var left = GetLeftNode(expression);
var right = GetRightNode(expression);
if (expression.NodeType == ExpressionType.Equal)
{
equalty = "=";
}
if (expression.NodeType == ExpressionType.AndAlso)
{
equalty = "AND";
}
if (expression.NodeType == ExpressionType.OrElse)
{
equalty = "OR";
}
if (expression.NodeType == ExpressionType.NotEqual)
{
equalty = "<>";
}
if (left is MemberExpression)
{
var leftMem = left as MemberExpression;
value = string.Format("({0}{1}'{2}')", leftMem.Member.Name, equalty, "{0}");
}
if (right is ConstantExpression)
{
var rightConst = right as ConstantExpression;
value = string.Format(value, rightConst.Value);
}
if (right is MemberExpression)
{
var rightMem = right as MemberExpression;
var rightConst = rightMem.Expression as ConstantExpression;
var member = rightMem.Member.DeclaringType;
var type = rightMem.Member.MemberType;
var val = member.GetField(rightMem.Member.Name).GetValue(rightConst.Value);
value = string.Format(value, val);
}
if (value == "")
{
var leftVal = GetValueAsString(left);
var rigthVal = GetValueAsString(right);
value = string.Format("({0} {1} {2})", leftVal, equalty, rigthVal);
}
return value;
}
private static Expression GetLeftNode(Expression expression)
{
dynamic exp = expression;
return ((Expression)exp.Left);
}
private static Expression GetRightNode(Expression expression)
{
dynamic exp = expression;
return ((Expression)exp.Right);
}
You can use the inbuilt extension methods of System.Linq to convert lambda expressions to SQL.
See the code below...
var Enames = emp.Employees.Select ( e => e.EmployeeName );
Console.WriteLine ( Enames );
The output which I got..
SELECT
[Extent1].[EmployeeName] AS [EmployeeName]
FROM [dbo].[Employee] AS [Extent1]
I had the same problem and started to solve it some time ago. Take a look on LambdaSql.
For now it contains basic scenarios for select clause and where filters. Setting fields, where, group by, having, order by, joins, nested queries are already supported. Insert, Update and Delete are going to be supported later.
Example:
var qry = new SqlSelect
(
new SqlSelect<Person>()
.AddFields(p => p.Id, p => p.Name)
.Where(SqlFilter<Person>.From(p => p.Name).EqualTo("Sergey"))
, new SqlAlias("inner")
).AddFields<Person>(p => p.Name);
Console.WriteLine(qry.ParametricSql);
Console.WriteLine("---");
Console.WriteLine(string.Join("; ", qry.Parameters
.Select(p => $"Name = {p.ParameterName}, Value = {p.Value}")));
Output:
SELECT
inner.Name
FROM
(
SELECT
pe.Id, pe.Name
FROM
Person pe
WHERE
pe.Name = #w0
) AS inner
---
Name = #w0, Value = Sergey
See more here https://github.com/Serg046/LambdaSql

Dynamic expression tree to filter on nested collection properties

I'm using Entity Framework and building queries using navigation properties dynamically.
For most of my use cases, the following works fine:
private static MethodCallExpression GetNavigationPropertyExpression<T>(string propertyName, int test,
ParameterExpression parameter, string subParameter)
{
var navigationPropertyCollection = Expression.Property(parameter, propertyName);
var childType = navigationPropertyCollection.Type.GetGenericArguments()[0];
var anyMethod = typeof(Enumerable).GetMethods().Single(m => m.Name == "Any" && m.GetParameters().Length == 2).MakeGenericMethod(childType);
var aclAttribute = GetAclAttribute(typeof(T), propertyName);
var childProperty = aclAttribute.ChildProperty;
var propertyCollectionGenericArg = childType;
var serviceLocationsParam = Expression.Parameter(propertyCollectionGenericArg, subParameter);
var left = Expression.Property(serviceLocationsParam, childProperty);
var right = Expression.Constant(test, typeof(int));
var isEqual = Expression.Equal(left, right);
var subLambda = Expression.Lambda(isEqual, serviceLocationsParam);
var resultExpression = Expression.Call(anyMethod, navigationPropertyCollection, subLambda);
return resultExpression;
}
I use a custom AclAttribute class assigned to properties via metadata type and partial classes. For navigation properties, a ChildProperty is provided so that the expression builder knows to look deeper for the desired property.
For example: the table Services references another table called ServiceLocations. I need the LocationId value(s) from the ServiceLocations reference. This part works fine.
My problem is when there is more than 1 nested property to go through. Another example: the table ServiceCategories references Services which, again, references ServiceLocations. Like before, I need the LocationId value(s) from ServiceLocations.
I've done this manually by using two "Any" methods, combining, and returning the resulting expression, but there will be times where navigation properties won't be collections, or a child of a navigation property may be a collection. For those cases, I need some kind of recursive option. I've been trying for a while now, and coming up short.
Since I mentioned it, here's the test method I put together for my second example. This works, but I'm violating DRY. (Note: I didn't name the tables):
private static MethodCallExpression GetNestedNavigationPropertyExpression(int test, ParameterExpression rootParameter)
{
var servicesProperty = Expression.Property(rootParameter, "tblServices");
var servicesParameter = Expression.Parameter(servicesProperty.Type.GetGenericArguments()[0], "ss");
var serviceLocationsProperty = Expression.Property(servicesParameter, "tblServiceLocations");
var serviceLocationsParameter = Expression.Parameter(serviceLocationsProperty.Type.GetGenericArguments()[0], "s");
var servicesAnyMethod = typeof(Enumerable).GetMethods().Single(m => m.Name == "Any" && m.GetParameters().Length == 2).MakeGenericMethod(servicesProperty.Type.GetGenericArguments()[0]);
var serviceLocationsAnyMethod = typeof(Enumerable).GetMethods().Single(m => m.Name == "Any" && m.GetParameters().Length == 2).MakeGenericMethod(serviceLocationsProperty.Type.GetGenericArguments()[0]);
var aclAttribute = GetAclAttribute(typeof(tblService), "tblServiceLocations");
var left = Expression.Property(serviceLocationsParameter, aclAttribute.ChildProperty);
var right = Expression.Constant(test, typeof(int));
var isEqual = Expression.Equal(left, right);
var subLambda = Expression.Lambda(isEqual, serviceLocationsParameter);
var endExpression = Expression.Call(serviceLocationsAnyMethod, serviceLocationsProperty, subLambda);
var intermediaryLamba = Expression.Lambda(endExpression, servicesParameter);
var resultExpression = Expression.Call(servicesAnyMethod, servicesProperty, intermediaryLamba);
return resultExpression;
}
With this it should be possible to build your queries:
public static Expression GetNavigationPropertyExpression(Expression parameter, int test, params string[] properties)
{
Expression resultExpression = null;
Expression childParameter, navigationPropertyPredicate;
Type childType = null;
if (properties.Count() > 1)
{
//build path
parameter = Expression.Property(parameter, properties[0]);
var isCollection = typeof(IEnumerable).IsAssignableFrom(parameter.Type);
//if it´s a collection we later need to use the predicate in the methodexpressioncall
if (isCollection)
{
childType = parameter.Type.GetGenericArguments()[0];
childParameter = Expression.Parameter(childType, childType.Name);
}
else
{
childParameter = parameter;
}
//skip current property and get navigation property expression recursivly
var innerProperties = properties.Skip(1).ToArray();
navigationPropertyPredicate = GetNavigationPropertyExpression(childParameter, test, innerProperties);
if (isCollection)
{
//build methodexpressioncall
var anyMethod = typeof(Enumerable).GetMethods().Single(m => m.Name == "Any" && m.GetParameters().Length == 2);
anyMethod = anyMethod.MakeGenericMethod(childType);
navigationPropertyPredicate = Expression.Call(anyMethod, parameter, navigationPropertyPredicate);
resultExpression = MakeLambda(parameter, navigationPropertyPredicate);
}
else
{
resultExpression = navigationPropertyPredicate;
}
}
else
{
//Formerly from ACLAttribute
var childProperty = parameter.Type.GetProperty(properties[0]);
var left = Expression.Property(parameter, childProperty);
var right = Expression.Constant(test, typeof(int));
navigationPropertyPredicate = Expression.Equal(left, right);
resultExpression = MakeLambda(parameter, navigationPropertyPredicate);
}
return resultExpression;
}
private static Expression MakeLambda(Expression parameter, Expression predicate)
{
var resultParameterVisitor = new ParameterVisitor();
resultParameterVisitor.Visit(parameter);
var resultParameter = resultParameterVisitor.Parameter;
return Expression.Lambda(predicate, (ParameterExpression)resultParameter);
}
private class ParameterVisitor : ExpressionVisitor
{
public Expression Parameter
{
get;
private set;
}
protected override Expression VisitParameter(ParameterExpression node)
{
Parameter = node;
return node;
}
}
Call it like:
var parameter = Expression.Parameter(typeof(A), "A");
var expression = ExpressionBuilder.GetNavigationPropertyExpression(parameter, 8,"CollectionOfB", "CollectionOfC", "ID");

Linq to Entities error

In MVVM, i am getting an entity set from the repository to viewmodel. While trying to access the elements of the entity, it throws an exception:
LINQ to Entities does not recognize the method 'InsurableRisk.Entities.QueriesParameter ElementAt[QueriesParameter](System.Linq.IQueryable`1[InsurableRisk.Entities.QueriesParameter], Int32)' method, and this method cannot be translated into a store expression.
Here is my code:
Repository:
public IQueryable<QueriesParameter> GetParams(int QKey)
{
IQueryable<QueriesParameter> param = (from Q in Context.QueriesParameters
where (Q.QueryKey == QKey)
select Q);
return param;
}
Service:
public IQueryable<QueriesParameter> GetParams(int QKey)
{
return _repository.GetParams(QKey);
}
ViewModel:
paramLabel = new string[] { "ParamLabel1", "ParamLabel2", "ParamLabel3", "ParamLabel4", "ParamLabel5", "ParamLabel6" };
param = new string[] { "Param1", "Param2", "Param3", "Param4", "Param5", "Param6" };
paramVisibility = new string[] { "ParamVisiblity1", "ParamVisiblity2", "ParamVisiblity3", "ParamVisiblity4", "ParamVisiblity5", "ParamVisiblity6" };
paramLabelVisibility = new string[] { "ParamLabelVisiblity1", "ParamLabelVisiblity2", "ParamLabelVisiblity3", "ParamLabelVisiblity4", "ParamLabelVisiblity5", "ParamLabelVisiblity6" };
private Dictionary<int, string> m_queryNames;
private Dictionary<int, string> m_ReadOnlyQueryNames;
private int m_SelectedQueryNames;
public int SelectedQueryNames
{
get
{
return m_SelectedQueryNames;
}
set
{
if (m_SelectedQueryNames != value)
{
m_SelectedQueryNames = value;
OnPropertyChanged("SelectedQueryNames");
var QKey = m_SelectedQueryNames;
var sqlQuery = _service.GetQuery(QKey);
var paramCount = _service.GetParamCount(QKey);
//code to make the run button visible and the parameters to be visible
m_Visibility = true;
IQueryable<QueriesParameter> param = _service.GetParams(QKey);
for (int i = 1; i <= paramCount; i++)
{
OnPropertyChanged(paramLabelVisibility[i]);
OnPropertyChanged(paramVisibility[i]);
QueriesParameter qParam = param.ElementAt(i); <!-- I get the exception here -->
m_LabelName = qParam.ParameterName;
OnPropertyChanged(paramLabel[i]);
//OnPropertyChanged(param[i]);
}
}
}
Any help as in why i am getting this error?
You are getting this error because ElementAt is not supported by LINQ to Entities (indeed, how you will translate it into SQL?). Here is list of Supported and Unsupported LINQ Methods.
You can enumerate over params instead:
IQueryable<QueriesParameter> param = _service.GetParams(QKey);
int i = 1; // btw why you are iterating from index 1? It should be zero!
foreach(var p in param)
{
OnPropertyChanged(paramLabelVisibility[i]);
OnPropertyChanged(paramVisibility[i]);
QueriesParameter qParam = p; // here
m_LabelName = qParam.ParameterName;
OnPropertyChanged(paramLabel[i]);
i++;
}
Another option - move query to client side by calling AsEnumerable() or ToList(). Then Linq to Objects will be used, where you can use ElementAt(index) method or via indexer [index]:
List<QueriesParameter> param = _service.GetParams(QKey).ToList();
//... your code
QueriesParameter qParam = param[i];

Categories