'IN' gives empty result - c# and cosmos - c#

I am trying to query the cosmos and the query works. The query looks like
'Select * from c where c.id IN ('123', '456')'.
Now in my c# code, I get empty result. The c# code looks like :
public void GetValue(IEnumerable<string> ids, string s)
{
StringBuilder sb = new();
_ = sb.Append("SELECT t.id FROM t ")
.Append("WHERE t.id IN (#items) ")
.Append("AND t.state != #state");
var queryDefinition = new QueryDefinition(sb.ToString())
.WithParameter("#items", ids)
.WithParameter("#state", s);
var results = GetQueryResults<TableName>(queryDefinition); // Get Empty Result
// Some logic based on results
}
// GetQueryResults query the container and gets the result for the tableName.
SO, I was able to conclude that the 'IN' query syntax is incorrect. Can anyone help me out.

The problem is here:
.Append("WHERE t.id IN (#items) ")
The list cannot be parameterized. One possiblity is to add the list items as separate parameters. There is an example of that here.
EDIT
I found the solution here
var querySpec = new SqlQuerySpec {
QueryText = "SELECT t.Id FROM t WHERE ARRAY_CONTAINS(#Ids, t.Id)",
Parameters = new SqlParameterCollection {
new SqlParameter {
Name = "#Ids",
Value = ids
}
}
}

Related

Execute a textual SQL query on an IQueryable

I am trying to convert IQueryable to IEnumerable using SQL query. I am not sure if it's possible.
var id = "123";
string queryString = "SELECT * FROM c WHERE c.ID = " + id;
var dataSource = new List<Book> {
new Book{ ID = "123", Title = "HarryPotter"}}.AsQueryable();
var expected = dataSource.ConvertToIEnumerable(queryString); //IEnumerable type
The dataSource variable has type of IQueryable. Is there any way to pass the queryString variable in order to convert the expected variable has type of IEnumerable?
What you are trying to do is to query List<T> in memory using sql. I do not believe that there is a built-in way in .NET Framework.
What you can do is to use LINQ that provides SQL-like or lambda syntax to collections.
var id = "123";
var dataSource = new List<Book>
{
new Book{ ID = "123", Title = "HarryPotter"}
};
var find = dataSource.Where(i => i.ID == id);

BaseQuery class missing in new NEST dll version NEST.1.1.2

What is the replacement of BaseQuery class in new version.
I couldn't find it anywhere.
My problem is how to generate syntax in c# for the search criteria as:
public class TextSearch
{
public string Headline {get;set;}
public string Summary {get;set;}
}
I need to search using text 'you', against two column as OR operator, Column 1 summary and Column 2 headline.
Earlier I was doing,
var orQuery = new List<BaseQuery>();
if (!string.IsNullOrEmpty(searchtext))
{
orQuery .Add(Query<TextSearch>.Terms("headline", searchOptions.text.ToLower().Split(' ')));
orQuery .Add(Query<TextSearch>.Terms("summary", searchOptions.text.ToLower().Split(' ')));
}
var finalQuery = new List<BaseQuery>();
finalQuery .Add(Query<TextSearch>.Bool(o => o.Should(orQuery.ToArray())));
Now this doesn't work.
Is there any better syntax for searching in new version.
The search criteria should using LIKE with OR,
e.g. summary LIKE '%you%' OR headling LIKE '%you%'
The documentation on the breaking changes in NEST 1.0 is pretty complete:
http://nest.azurewebsites.net/breaking-changes.html
We renamed BaseQuery to QueryContainer
The query can be:
client.Search<TextSearch>(s=>s
.Query(q=>
q.Terms("headline", words)
|| q.Terms("summary", words)
)
)
If words is empty or null that part is not rendered see the conditionless query section here:
http://nest.azurewebsites.net/nest/writing-queries.html
#Martijn Laarman
Since we have numerous filter criteria that will be dynamic based on user selected filter,
I'm constructing Filter Query in amethod based on user slelcted filter and then pass it to Search<> method as:
QueryContainer mainQuery = null;
if (!string.IsNullOrEmpty(searchOptions.SearchText))
{
var headline = Query<T>.Terms("headline", searchOptions.Headline.ToLower());
var summary = Query<T>.Terms("fullSummary", searchOptions.Summary.ToLower());
mainQuery &= (headline || summary);
}
if (searchOptions.FromDate != DateTime.MinValue && searchOptions.ToDate != DateTime.MinValue)
{
var dateFilter = Query<T>.Range(
r => r.OnField("processedDate").GreaterOrEquals(searchOptions.FromDate, ElasticDateFormat).LowerOrEquals(searchOptions.ToDate, ElasticDateFormat));
mainQuery &= dateFilter;
}
var result = Client.Search<T>(s => s.Query(mainQuery ).Size(Int32.MaxValue));
Here Client is a property that returns ElasticClient object.
Hope thats the correct way of doing.

Passing parameter to LINQ query

I have a method like below:
public void GetUserIdByCode(string userCode)
{
var query = from u in db.Users
where u.Code == userCode // userCode = "LRAZAK"
select u.Id;
var userId = query.FirstOrDefault(); // userId = 0 :(
}
When I ran the code, I got the default value of 0 assigned to userId meaning the Id was not found.
However, if I changed the userCode with a string like below, I will get the value I want.
public void GetUserIdByCode(string userCode)
{
var query = from u in db.Users
where u.Code == "LRAZAK" // Hard-coded string into the query
select u.Id;
var userId = query.FirstOrDefault(); // userId = 123 Happy days!!
}
My question is why passing the parameter into the LINQ query does not work?
When I stepped into the code, I got the SQL statement like so:
// Does not work...
{SELECT "Extent1"."LOGONNO" AS "LOGONNO"FROM "DEBTORSLIVE"."DEBTORS_LOGONS" "Extent1"WHERE ("Extent1"."LOGONCODE" = :p__linq__0)}
The hard-coded LINQ query (the working one) gives an SQL statement as below:
// Working just fine
{SELECT "Extent1"."LOGONNO" AS "LOGONNO"FROM "DEBTORSLIVE"."DEBTORS_LOGONS" "Extent1"WHERE ('LRAZAK' = "Extent1"."LOGONCODE")}
What would be the solution?
As a work-around, I use Dynamic Linq.
The code below is working for me.
public void GetUserIdByCode(string userCode)
{
string clause = String.Format("Code=\"{0}\"", userCode);
var userId = db.Users
.Where(clause)
.Select(u => u.Id)
.FirstOrDefault();
}
The database query returns an object of User with Code and Id as properties. This is defined in one of my classes.
Here is syntax that will work to pass an argument to a LINQ query.
Not sure how many people will be searching this topic so many years later, but here's a code example that gets the job done:
string cuties = "777";
// string collection
IList<string> stringList = new List<string>() {
"eg. 1",
"ie LAMBDA",
"777"
};
var result = from s in stringList
where (s == cuties)
select s;
foreach (var str in result)
{
Console.WriteLine(str); // Output: "777"
}

Subquery using LINQ to SQL

I am using LINQ to SQL in my C# tutorial project but I have basic knowledge of it.
I made a SQL query like this:
SELECT ID,HeroName,HeroRarity,Initiative,Attack,Attack1
FROM CharactersName
WHERE ID IN(
SELECT HeroID
FROM Hero_Group
WHERE GroupID=1
)
(Hero_Group) is a table to deal with a many-to-many relation between (CharactersName) table and another table named (Groups) where a character can be in more than one group.
I tried to write it in LINQ like this:
void FilterGroup()
{
HDAEntities db = new HDAEntities();
var query = from obj in db.CharactersNames
where obj.ID == from obj2 in db.Hero_Group
where obj2.GroupID == comboBox1.SelectedIndex
select new
{
obj2.GroupID
}
select new
{
obj.ID,
obj.HeroName,
obj.HeroRarity,
obj.Initiative,
obj.Attack,
obj.Attack1
};
}
But of course this is gibberish.
Can someone help me, please ? (be informed that I have little knowledge of LINQ to SQL)
~TIA~
You can do it like this:
void FilterGroup()
{
HDAEntities db = new HDAEntities();
var subQuery = db.Hero_Group.Where(h => h.GroupID == comboBox1.selectedIndex)
.Select(h => h.GroupID);
var query = from obj in db.CharactersNames
where subQuery.Contains(obj.ID)
select new
{
obj.ID,
obj.HeroName,
obj.HeroRarity,
obj.Initiative,
obj.Attack,
obj.Attack1
};
var result = query.ToList(); // this is where your query and subquery are evaluated and sent to the database
db.Dispose();
db = null;
}
Note that the subQuery is not evaluated until you call ToList(). You also need to dispose the object (or try the using statement to create the HDAEntities object). Also, make sure you don't dispose the db before evaluating the query (calling ToList after Dispose will throw an exception).
var query = from obj in db.CharactersNames
where (from obj2 in db.Hero_Group
where obj2.GroupID == comboBox1.SelectedIndex
select new {obj2.GroupID}).Contains(obj.ID)
select new
{
obj.ID,
obj.HeroName,
obj.HeroRarity,
obj.Initiative,
obj.Attack,
obj.Attack1
};
var query = from obj in db.CharactersNames
where (from obj2 in db.Hero_Group
where obj2.GroupID == comboBox1.SelectedIndex
select new {obj2.GroupID}).Contains(obj.ID)
select new
{
obj.ID,
obj.HeroName,
obj.HeroRarity,
obj.Initiative,
obj.Attack,
obj.Attack1
};

String.Split in a Linq-To-SQL Query?

I have a database table that contains an nvarchar column like this:
1|12.6|18|19
I have a Business Object that has a Decimal[] property.
My LINQ Query looks like this:
var temp = from r in db.SomeTable select new BusinessObject {
// Other BusinessObject Properties snipped as they are straight 1:1
MeterValues = r.MeterValues.Split('|').Select(Decimal.Parse).ToArray()
};
var result = temp.ToArray();
This throws an NotSupportedException: Method 'System.String[] Split(Char[])' has no supported translation to SQL.
That kinda sucks :) Is there any way I can do this without having to add a string property to the business object or selecting an anonymous type and then iterating through it?
My current "solution" is:
var temp = from r in db.SomeTable select new {
mv = r.MeterValues,
bo = new BusinessObject { // all the other fields }
};
var result = new List<BusinessObject>();
foreach(var t in temp) {
var bo = t.bo;
bo.MeterValues = t.mv.Split('|').Select(Decimal.Parse).ToArray();
result.Add(bo);
}
return result.ToArray(); // The Method returns BusinessObject[]
That's kinda ugly though, with that temporary list.
I've tried adding a let mv = r.MeterValues.Split('|').Select(Decimal.Parse).ToArray() but that essentially leads to the same NotSupportedException.
This is .net 3.5SP1 if that matters.
You need to force the select clause to run on the client by calling .AsEnumerable() first:
var result = db.SomeTable.AsEnumerable().Select(r => new BusinessObject {
...
MeterValues = r.MeterValues.Split('|').Select(Decimal.Parse).ToArray()
}).ToList();
You can't use split, but in this scenario you can do the following:
// Database value is 1|12.6|18|19
string valueToFind = "19";
var temp = from r in db.SomeTable.Where(r => ("|" + r.MeterValues + "|").Contains("|" + valueToFind + "|"));
This code adds outer pipes (|) to the database value on the fly inside the query so you can do start, middle, and end value matches on the string.
For example, the above code looks for "|19|" inside "|1|12.6|18|19|", which is found and valid. This will work for any other valueToFind.
You don't need to use a temporary list:
var query = from r in db.SomeTable
select new
{
r.Id,
r.Name,
r.MeterValues,
...
};
var temp = from x in query.AsEnumerable()
select new BusinessObject
{
Id = x.Id,
Name = x.Name,
MeterValues = x.mv.Split('|').Select(Decimal.Parse).ToArray(),
...
};
return temp.ToArray();
Unfortunately its the IQueryable you are using (Linq to SQL) that is not supporting the Split function.
You are really only left with the IEnumerable (Linq to Objects) support for it in this case. You second code snippet is what you need to do, or something like...
var temp = (from r in db.SomeTable select new {
mv = r.MeterValues,
bo = new BusinessObject { // all the other fields }
}).AsEnumerable().Select(blah, blah) ;

Categories