What is the linq equivalent of the below sql query - c#

select Productid from categories where `categoryname` in `('abc','def','ghi')`;
I have tried this:
var res = from catg in db.Categories where catg.CategoryId.ToString().Contains(SelectedProducts) select catg;
But this doesnt seem to work...

Assuming SelectedProducts is an array of product ids (integers):
var cats = db.Categories.Where(o => SelectedProducts.Contains(o.CategoryId));
var pids = cats.Select(o => o.ProductId);
Reason: SQL IN operator is implemented oppositely in LINQ to SQL. The question highlights a common mistake in LINQ developers trying to translate from SQL, expecting an [attribute] [operator] [set] syntax.
Using an abstract set language we can highlight syntax differences
SQL uses a "Element is included in Set" syntax
LINQ uses a "Set contains Element" syntax
So any IN clause must be reverted using the Contains operator. It will translate to attribute IN (SET) anyways.

You need to use Contains on SelectedProducts
var res = from catg in db.Categories where
SelectedProducts.Contains(catg.categoryname) select catg.Productid;
Using method notation
var res = db.Categories.Where(catg => SelectedProducts
.Contains(catg.categoryname)).Select(catg.Productid);

The equivalence of a SQL IN with IEnumerable.Contains():
var res = from catg in db.Categories
where new[] {"abc","def","ghi"}.Contains(catg.categoryname)
select catg.Productid
Or lambda
db.Categories.Where(x => new[] {"abc","def","ghi"}.Contains(x.categoryname)).Select(c => c.ProductId);

Related

Dynamic Linq 'contains' clause without using placeholder

The syntax given for contains clause is
ids = new int[] {1,2,3,4};
dataContext.Table.Where("#0.Contains(id)", ids);
But what I want is
dataContext.Table.Where("{1,2,3,4}.Contains(id)"); //getting exception here
[ERROR] Expression expected (at index 0)
I need this because the where clause my or may not use the contains method. it depends on how user acts.
so I got the answer for this after tinkering for sometime. So posting the answer here.
dataContext.Table.Where("new Int[]{1,2,3,4}.Contains(id)");
You can use whatever datatype you need. I use reflection to find datatype and use that accordingly.
try code:
int[] ids= {1,2,3,4};
dataContext.Table.Where(c=>c.ids.Contains(t.id)).ToList();
Or
var result= (from p in dataContext.Table.AsEnumerable()
join q in ids on p.id equals q
select p).Distinct() .ToList();

LINQ grouping - get other, not grouped properties

I have little problem with my LINQ query (nHibernate)
I need to have count of objects znak with equal property Symbol
My query:
var tmp = (from znak in sesja.Query<Znak>()
group znak by znak.Symbol into r
select new { Name= r.Key.Name, SUM= r.Count() });
This query works, but I need to make object contains other properties of znak class.
In this case: select new { Name= r.Key.Name, SUM= r.Count() }); i can make new objects only from r.Key, (Symbol property). But I need other properties in my new object.
Is it possible ?
I recommend using lambda Linq syntax:
var items = sesja.Query<Znak().AsEnumerable();
var newList = items.GroupBy(x=>x.Symbol).Select(
x=> new { Name=x.Key.Name, Count = x.Count(), Items = x.ToList() });
read more about Linq syntax LINQ: Dot Notation vs Query Expression
I think that lambda syntax is more readable and looks much cleaner in code because it's more c# style not sql style.
Of course there will be no difference in IL code, always you can install tools like resharper, they can convert lambda syntax to sql-like syntax.
Try something like
var tmp = (from znak in sesja.Query<Znak>()
group znak by znak.Symbol into r
select new { Name= r.Key.Name, SUM= r.Count(), Items = r.ToList() });
Items property will contain actual objects in the group.

LINQ Projected Filtering C#

I want to filter my LINQ query based on an included table but am having some trouble.
Here is the original statement, which works:
return
this.ObjectContext.People.
Include("Careers").
Include("Careers.Titles").
Include("Careers.Titles.Salaries");
Now I'm trying to filter on Careers using projected filtering but am having trouble. It compiles but it leaves out the Titles and Salaries tables, which causes runtime errors, and I can't seem to add those tables back in:
var query1 = (
from c in
this.ObjectContext.People.
Include("Careers").
Include("Careers.Titles").
Include("Careers.Titles.Salaries")
select new
{
c,
Careers = from Careers in c.Careers
where Careers.IsActive == true
select Careers
});
var query = query1.AsEnumerable().Select(m => m.c);
return query.AsQueryable();
How can I include the titles and salaries tables in the filtered query?
You can simplify your query considerably, which should resolve your issue. I'm assuming that you want all people with at least 1 active career:
var query =
from c in
this.ObjectContext.People.
Include("Careers").
Include("Careers.Titles").
Include("Careers.Titles.Salaries")
where c.Careers.Any(c => c.IsActive);
return query;
I would try something like,
var query = from p in ObjectContext.People
join c in ObjectContext.Careers on p equals c.Person
where c.IsActive
select p;

Mixing LINQ to SQL with properties of objects in a generic list

I am trying to accomplish something like this query:
var query = from a in DatabaseTable
where listOfObjects.Any(x => x.Id == a.Id)
select a;
Basically, I want to filter the results where a.Id equals a property of one of the objects in the generic list "listOfObjects". I'm getting the error "Local sequence cannot be used in LINQ to SQL implementation of query operators except the Contains() operator."
Any ideas on how to filter this in an easily readable way using "contains" or another method?
Thanks in advance.
Just project your local list into a list of the specific items you need to filter on:
var listOfIds = listOfObjects.Select(o => o.Id);
var query =
from a in DatabaseTable
where listOfIds.Contains(a.Id)
select a;
var listOfIds = listOfObjects.Select(x => x.Id).ToList();
var query = from a in DatabaseTable
where listOfIds.Contains(a.Id)
select a;

Linq: using StringComparer with GroupBy/Distinct in query syntax

I have this (XLinq) query and was wondering how to convert it to the query syntax:
var grouped = doc.Descendants()
.GroupBy(t => t.Element(ns + "GroupingAttr").Value, StringComparer.OrdinalIgnoreCase);
This is the query syntax without the StringComparer:
var grouped = from t in doc.Descendants()
group t by t.Element(ns + "GroupingAttr").Value into group
select group
My groupby is a little more complicated than this, so I prefer to use the key of the group instead of introducing a new property.
This is what I tried, but doesn't work because the let "key" is not available in the context of the select (I've uses my more complicated key definition to illustrate the fact I don't want to repeat this in the select):
var grouped = from t in doc.Descendants()
let key = ((t.Name != ns + "SomeElementName") ? t.Element(ns + "SomeAttribute") : t.Element(ns + "SomeOtherAttribute")).ElementValueOrDefault("Empty group")
group t by key.ToUpper() into g
select new { Name = key, Items = g };
In the end, case-sensitivity was not important because I could presume that all casings were the same...
Related question: LINQ Distinct operator ignore case?
I don't think you can use the comparer within the query syntax, however you could call ToUpper on your value. This will then ignore case for you. As a side note using ToUpper is more efficient than using ToLower, so ToUpper would be the way to go.
The C# team were very sparse with what they introduced into the query syntax, so for anything like this you'll have to use the extension methods syntax.
var grouped = from t in doc.Descendants()
group t by t.Element(ns + "GroupingAttr").Value into MyGroup
select MyGroup.Key

Categories

Resources