Linq Queryable Expression Tree: SqlException: Incorrect syntax near '&' - linq

I am getting an error: { SqlException: Incorrect syntax near '&' } which I cannot seem to figure out. I have a class QuestionResult (seen below).
public class QuestionResult
{
public int Id { get; set; }
public float? Result { get; set; }
public string ResultText { get; set; }
//Foreign Keys & Connections
public virtual SurveyResult SurveyResult { get; set; }
public virtual Question Question { get; set; }
public int QuestionId { get; set; }
public int SurveyResultId { get; set; }
}
which I wish to filter by QuestionId & Result, for example {QuestionId == 48 && Result >= 24}. The issue appears to be around using Expression.And. I tried this test without using it, using just one of the conditions and it ran fine. I have previously used Expression.And and it has worked.
public static List<int> GetIdList()
{
IQueryable<QuestionResult> questionResultList = _context.QuestionResult.AsQueryable();
var questionResult = Expression.Parameter(typeof(QuestionResult), "qr");
MemberExpression questionId = Expression.Property(questionResult, "QuestionId");
MemberExpression result = Expression.Property(questionResult, "Result");
var conditionA = Expression.Equal(questionId, Expression.Constant(48));
var conditionB = Expression.GreaterThanOrEqual(result, Expression.Convert(Expression.Constant(24), result.Type));
var and = Expression.And(conditionA, conditionB);
var predicateBody = Expression.Lambda<Func<QuestionResult, bool>>(and, questionResult);
MethodCallExpression query = Expression.Call(
typeof(Queryable),
"Where",
new Type[] { questionResultList.ElementType },
questionResultList.Expression,
predicateBody
);
var questionResultIdList = questionResultList.Provider.CreateQuery<QuestionResult>(query).Select(i => i.Id).ToList();
return questionResultIdList;
}
Can you see somewhere that I have gone wrong with this? Debugging the query before it has run shows:
{value(Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[SurveyV3.Models.DatabaseModels.QuestionResult]).Where(qr => ((qr.QuestionId == 48) And (qr.Result >= Convert(24))))}
which looks right to me. I have been using questions on here and this Microsoft page for assistance https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/expression-trees/how-to-use-expression-trees-to-build-dynamic-queries
Thanks, Oj

var and = Expression.And(conditionA, conditionB);
Expression.And does a bitwise AND operation.
You want Expression.AndAlso which does a logical AND.

Related

Increment a value when conditions are met, otherwise set to zero

Given a list of strings, I'd like to create a list of the following object
class LineInfo
{
public string line { get; set; }
public bool isSearchMatch { get; set; }
public int searchMatchNumber { get; set; }
}
Where I'd like searchMatchNumber to have 1 for the 1st match, 2 for the 2nd, etc. Otherwise it can be zero
I set this up like so
IEnumerable<string> allLines; //pulled in from somewhere
IEnumerable<LineInfo> logInfoLines = allLines.Select((l, i) => new LineInfo
{
line = l,
isSearchMatch = l.IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0
});
How can I set searchMatchNumber?
LINQ queries should not cause side effects like this. If you'd add an OrderBy you'd get a different result. I wouldn't use LINQ for this, you could provide a method:
class LineInfo
{
public string line { get; set; }
public bool isSearchMatch { get; set; }
public int searchMatchNumber { get; set; }
public static IEnumerable<LineInfo> GetSearchResult(IEnumerable<string> allLines, string search)
{
int matchCounter = 0;
var lineInfoList = new List<LineInfo>();
foreach (string line in allLines)
{
bool isMatch = line.IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0;
var li = new LineInfo
{
line = line,
isSearchMatch = isMatch,
searchMatchNumber = isMatch ? ++matchCounter : -1 // or whatever
};
lineInfoList.Add(li);
}
return lineInfoList;
}
}

RavenDB, Linq: Build an expression from a Property inside a nested hierarchy

I stored the objects of the following classes in a ravendb database:
public class Continent
{
public string Id { get; set; }
public string Name { get; set; }
public List<Country> Countries { get; set; }
}
public class Country
{
public string Name { get; set; }
public List<Province> Provinces { get; set; }
}
public class Province
{
public string Name { get; set; }
public List<City> Cities { get; set; }
}
public class City
{
public string Name { get; set; }
public string Address { get; set; }
}
I want to write a method that searches Continents having a specific city. The latter is a parameter of my method. In this method, I want to execute a dynamic query like the following: query= session.Query().Where(ConditionOnTheSearchedCity). But I can not formulate the Expression "ConditionOnTheSearchedCity" because I can not iterate till the Name of each City. In fact, to create an expression based on the Name of the City, I've tried the following which is not working:
ParameterExpression parameterExpression = Expression.Parameter(typeof(Continent), "p");
Expression NameExpression = Expression.PropertyOrField(
Expression.PropertyOrField(
Expression.PropertyOrField(
Expression.PropertyOrField(parameterExpression, "Countries"), "Provinces"),
"Cities"),
"Name");
Can you please help me? Thanks in advance
Why are you going to all the trouble of dynamically building Linq?
Why not just use the RavenDB's DocumentQuery API which allows you to easily build queries dynamically?
As I mentioned in the comments, the question is too broad, so I'll give you just a starting point by providing an example. For more information, take a look at How to: Use Expression Trees to Build Dynamic Queries.
Let have a parameter string cityName and want a filter like this
Expression<Func<Continent, bool>> filter = continent =>
continent.Countries.Any(country =>
country.Provinces.Any(province =>
province.Cities.Any(city => city.Name == cityName)));
It can be build dynamically like this
var city = Expression.Parameter(typeof(City), "city");
var cityCondition = Expression.Equal(Expression.PropertyOrField(city, "Name"), Expression.Constant(cityName));
var province = Expression.Parameter(typeof(Province), "province");
var provinceCondition = Expression.Call(
typeof(Enumerable), "Any", new[] { city.Type },
Expression.PropertyOrField(province, "Cities"),
Expression.Lambda(cityCondition, city));
var country = Expression.Parameter(typeof(Country), "country");
var countryCondition = Expression.Call(
typeof(Enumerable), "Any", new[] { province.Type },
Expression.PropertyOrField(country, "Provinces"),
Expression.Lambda(provinceCondition, province));
var continent = Expression.Parameter(typeof(Continent), "continent");
var continentCondition = Expression.Call(
typeof(Enumerable), "Any", new[] { country.Type },
Expression.PropertyOrField(continent, "Countries"),
Expression.Lambda(countryCondition, country));
var filter = Expression.Lambda<Func<Continent, bool>>(continentCondition, continent);

Dynamic LINQ: Comparing Nested Data With Parent Property

I've a class with following structure:
public class BestWayContext
{
public Preference Preference { get; set; }
public DateTime DueDate { get; set; }
public List<ServiceRate> ServiceRate { get; set; }
}
public class ServiceRate
{
public int Id { get; set; }
public string Carrier { get; set; }
public string Service { get; set; }
public decimal Rate { get; set; }
public DateTime DeliveryDate { get; set; }
}
and I've dynamic linq expression string
"Preference != null && ServiceRate.Any(Carrier == Preference.Carrier)"
and I want to convert above string in Dynamic LINQ as follows:
var expression = System.Linq.Dynamic.DynamicExpression.ParseLambda<BestWayContext, bool>(condition, null).Compile();
But it showing following error:
Please correct me what am I doing wrong?
It looks like you wanted to do something like this:
var bwc = new BestWayContext
{
Preference = new Preference { Carrier = "test" },
DueDate = DateTime.Now,
ServiceRate = new List<ServiceRate>
{
new ServiceRate
{
Carrier = "test",
DeliveryDate = DateTime.Now,
Id = 2,
Rate = 100,
Service = "testService"
}
}
};
string condition = "Preference != null && ServiceRate.Any(Carrier == #0)";
var expression = System.Linq.Dynamic.DynamicExpression.ParseLambda<BestWayContext, bool>(condition, bwc.Preference.Carrier).Compile();
bool res = expression(bwc); // true
bwc.ServiceRate.First().Carrier = "test1"; // just for testing this -> there is only one so I've used first
res = expression(bwc); // false
You want to use Preference which belong to BestWayContext but you didn't tell the compiler about that. If i write your expression on Linq i will do as follows:
[List of BestWayContext].Where(f => f.Preference != null && f.ServiceRate.Where(g => g.Carrier == f.Preference.Carrier)
);
As you see i specified to use Preference of BestWayContext.

How can I use be generic to result of linq query?

Be first, my English is not very good. So I am sorry about that. :)
My question as the title. I have two tables on my database:
Siniflar (SinifId, SinifAdi, Kapasite, OgretmenId)
Ogretmenler (OgretmenId, Ad, Soyad, Brans)
Query:
var siniflar = (from s in db.Siniflar
join o in db.Ogretmenler
on s.OgretmenId equals o.OgretmenId
select new { s.SinifId, s.SinifAdi, s.Kapasite, o.Ad }).ToList();
I want to use the result of the query as a generic, like this:
public List<Siniflar> SiniflariListele()
{
var siniflar = (from s in db.Siniflar
join o in db.Ogretmenler
on s.OgretmenId equals o.OgretmenId
select new { s.SinifId, s.SinifAdi, s.Kapasite, o.Ad }).ToList();
return siniflar;
}
But I get an error. Because the result is anonymous types.
Error: Cannot implicitly convert type System.Collections.Generic.List<AnonymousType#1> to System.Collections.Generic.List<Entity.Siniflar>
How Can I use be generic result. What Can I do for that?
I changed question:
Class:
public class RSiniflar
{
public int SinifId { get; set; }
public string SinifAdi { get; set; }
public int Kapasite { get; set; }
public string OgretmenAdiSoyadi { get; set; }
}
Metod:
public List<RSiniflar> SiniflariListele()
{
List<RSiniflar> siniflar = (from s in db.Siniflar
join o in db.Ogretmenler
on s.OgretmenId equals o.OgretmenId
select new RSiniflar
{
SinifId = s.SinifId,
SinifAdi = s.SinifAdi,
Kapasite = s.Kapasite,
OgretmenAdiSoyadi = o.Ad + ' ' + o.Soyad
}).ToList();
return siniflar;
}
But now error to query: Unable to create a constant value of type 'System.Object'. Only primitive types or enumeration types are supported in this context.
I think, there are a problem on my query... I get an error same when query to var type...
You can return typed list, but you can't return a list of anonymous type. So you need to create a class which will handle your results:
public class A
{
public int SinifId { get; set; }
public int SiniAdi { get; set; }
public int Kapasite { get; set; }
public int Ad { get; set; }
}
And then use it in your query, instead of anonymous objects:
public List<A> SiniflariListele()
{
var siniflar = (from s in db.Siniflar
join o in db.Ogretmenler
on s.OgretmenId equals o.OgretmenId
select new A {
SinifId = s.SinifId,
SinifAdi = s.SinifAdi,
Kapasite = s.Kapasite,
Ad = o.Ad
}).ToList();
return siniflar;
}
You could do the same with an existing class (e.g. Siniflar), but you have to be sure that this class has all necessary properties.
Rather than using new { property1, property2 }, create new Siniflar's in your select.
E.g.
select new Siniflar() {
SinifId = s.SinifId,
SinifAdi = s.SinifAdi,
Kapasite = s.Kapasite }).ToList()
Note: as lazyberezovsky mentioned, your mapping seems to be flawed, as Siniflar does not contain the property Ad.

How to use dynamic linq to query through nested arrays?

If I have class structure as follows:
private class A
{
int afoo { get; set; }
B[] bList { get; set; }
}
private class B
{
String bfoo { get; set; }
C[] cList { get; set; }
}
private class C
{
String cfoo { get; set; }
int cfoo2 { get; set; }
}
public class Master
{
A[] aList;
//qry for all where A.B.C.cfoo = "test"
}
How would I construct a dynamic LINQ statement to query for items in class C? Something like this
1) var qry = aList.blist.clist.AsQueryable().Where("cfoo = \"Test\"").Select();
My ultimate solution would be to pass the entire path in the dynamic part like this:
2) var qry = aList.AsQueryable().Where("bList.cList.cFoo = ""Test"").Select();
But from what I have tried you can not have the nested objects in the Where. So I am going to live with using templates to build the methods as in 1) above.
[Also, I am using the dynamic library from Scott Gu for the dynamic part.]
But, I can't get that to work. Any suggestions?
Thanks!
aList.SelectMany(a => a.bList)
.SelectMany(b => b.cList)
.Where(c => c.cfoo == "\"Test\"");
Try this:
aList.SelectMany(a => a.bList.SelectMany(b => b.cList))
.Where(c => c.cf002 == "Test")
.Select();

Resources