Entity Framework LINQ query construction - linq

I'm learning EF and LINQ while working on an API for a project
While in most case EF and LINQ made my coding easier this specific case is different.
I have a list of integers and i have to query my DB including all int inside
the list [10,2,23]
var queryable = (from p in db.plants
where p.plant_id == 10
|| p.plant_id == 2
|| p.plant_id == 23
select p)
.ToList();
but the list is created at runtime and the number of items inside is variable
so what's the method to use for creating the query?

You can use the Contains() function on an IEnumerable of your required ids. Entity Framework will convert this to a SQL IN clause so that it is an nice efficient query.
So this would lead your example to be:
var plantIds = new List<int> {10, 2, 23};
var queryable = (from p in db.plants
where plantIds.Contains(p.plant_id)
select p)
.ToList();

Related

Can this Aggregate Lambda expression be converted to a LINQ query?

I have a list of integers summed by an Aggregate method using a Lambda expression:
var mylist = new int[] { 3, 4, 5 };
var result = mylist.Aggregate((a, b) => a + b);
As I understand it, a Lambda expression can always be converted to a LINQ query. How would such a LINQ query look for my example?
EDIT: I understand .Sum may be better to add the numbers in my example. But I would really like to know how this Aggregate will look with a LINQ Query instead.
It already IS a LINQ query, Aggregate is a LINQ operator, i'm assuming what you meant was how it would look like in the LINQ comprehension syntax? The comprehension syntax only has a few built in features (select , where, multiple selects, groupby etc), it doesn't have all operators built in so when you need one of those (such as aggregate) you wrap it around parenthèses and keep going with the regular syntax. Since there is nothing there except aggregate it's not possible to give an example so i'll go from a different query:
var mylist = new int[] { 3, 4, 5, 6, 7, 8 };
var result = mylist
.Where(item=>item %2 == 0)
.Aggregate((a, b) => a + b);
var ComprehensiveResult =
(from item in mylist
where item % 2 == 0
select item)
.Aggregate((a, b) => a + b);
Comprehensive syntax is more of a "LINQ for people coming from SQL introduction", there's nothing you can do in it that you can't do with plain using the operators but the reverse isn't true as not all operators have built in replacements. The only thing that comes to mind where Comprehensive syntax is better (aside from personal taste) is multiple selects to generate a cartesian product which is much harder to maintain in plain method syntax.
In this case Aggregate function adds numbers each other. So, the equivalent function is SUM:
var qry = mylist.Sum(x=>x);
or
var qry = (from n in mylist select n).Sum();
[EDIT]
OP has added extra information to the question without informing me about that.
Yes, it's possible to "convert" Aggregate function into linq query, but extension method is needed. See this article: Cumulating values with LINQ

EF - Linq Expression and using a List of Ints to get best performance

So I have a list(table) of about 100k items and I want to retrieve all values that match a given list.
I have something like this.
the Table Sections key is NOT a primary key, so I'm expecting each value in listOfKeys to return a few rows.
List<int> listOfKeys = new List<int>(){1,3,44};
var allSections = Sections.Where(s => listOfKeys.Contains(s.id));
I don't know if it makes a difference but generally listOfKeys will only have between 1 to 3 items.
I'm using the Entity Framework.
So my question is, is this the best / fastest way to include a list in a linq expression?
I'm assuming that it isn't better to use another .NETICollection data object. Should I be using a Union or something?
Thanks
Suppose the listOfKeys will contain only small about of items and it's local list (not from database), like <50, then it's OK. The query generated will be basically WHERE id in (...) or WHERE id = ... OR id = ... ... and that's OK for database engine to handle it.
A Join would probably be more efficient:
var allSections =
from s in Sections
join k in listOfKeys on s.id equals k
select s;
Or, if you prefer the extension method syntax:
var allSections = Sections.Join(listOfKeys, s => s.id, k => k, (s, k) => s);

How can I use custom expressions in DevArt LINQ to Entities and also use query comprehension syntax?

I've got a situation where I need to use a custom expression in a LINQ to Entities query (because I want to have custom logic that L2E wouldn't otherwise understand:
var query = db.MyTable.Where(MyPredicateExpression)
But I'd rather use query comprehension syntax:
var query = from x in db.MyTable where [x matches the predicate of MyPredicateExpression]
I know this is possible, because L2E supports it in other places:
var query = from x in db.MyTable where x.Length > 10
How do they make that work?
Edit: I'm using devart's LinqConnect for Oracle, which may behave somewhat differently than Microsoft L2E.
Entity Framework and LINQ to SQL do not support this scenario, because the translation of MyPredicateExpression should be added to expression tree translator.
I recommend you to create a stored function performing the predicate check and add this function to DataContext. You will be able to use a query like the following in this case:
var query = from x in db.MyTable where context.MyPredicateFunction(x.Field) select x;
Update. Here is the updated query that takes into account your comments:
int[] values = new int[] { 1, 2, 3 };
var query = from x in db.MyTable where values.Contains(x.AuditState) select x;
Update 2. You can add a Queryable property to your context that will be obtaining the necessary set of MyTable objects as shown in the following example:
public partial class MyDataContext {
IQueryable<MyTable> GetSpecialTables {
get {
int[] values = new int[] { 1, 2, 3 };
return this.MyTables.Where(x => values.Contains(x.AuditState));
}
}
}
Replace MyDataContext with the actual name of your context.
If I understand the problem correctly, you can either use an extension method OR call a function that returns a bool.

LINQ queries with many-to-many tables in Entity Data Model

I'm trying to use LINQ to query the following Entity Data Model
based on this db model
I'd like to be able to pull a list of products based on ProductFacets.FacetTypeId.
Normally, I'd use joins and this wouldn't be a problem but I don't quite understand how to query many-to-many tables under the Entity DataModel.
This is an example sql query:
select p.Name, pf.FacetTypeId from Products p
inner join ProductFacets pf on p.ProductId = pf.ProductId
where pf.FacetTypeId in(8, 12)
Presuming EF 4:
var facetIds = new [] { 8, 12 };
var q = from p in Context.Products
where p.FacetTypes.Any(f => facetIds.Contains(f.FacetTypeId))
select p;
In EF (assuming the mapping is done correctly), joins are hardly ever used; navigation properties are used instead.
Your original SQL returns a tuple with repeated Name entries. With LINQ, it's often easier
to "shape" the queries into non-tuple results.
The following should be the same as the SQL, only instead of returning (Name, FacetTypeId) pairs with repeated Names, it will return a type that has a Name and a sequence of FacetTypeIds:
var facetIds = new [] { 8, 12 };
var result = from p in db.Products
select new
{
p.Name,
FacetTypeIds = from pf in p.FacetTypes
where pf.FacetTypeId == 8 || pf.FacetTypeId == 12
select pf.FacetTypeId,
};

Does LINQ Support Composable "OR Queries"?

In another posting: Does Linq-To-Sql support composable queries there was discussion on how to compose/concat where clauses dynamically. This appears to be done with an "AND" (i.e. the first where clause and the second where clause are joined by an AND). What I am wondering is if there is a way to compose Linq queries with an OR.
Example:
var people = from p in Person
where p.age < 18
select p
var otherPeople = from p in people
where p.firstName equals "Daniel"
select p
This gives people with a first name of "Daniel" and that are under 18. I'm looking for the syntax to join these to find people who have a first name of "Daniel" or are under 18.
Note: I am using ADO.net Data Services so I do not have .Contains() available to me.
EDIT: The Union Suggestion (by Garry Shutler) is exactly what I am looking for functionality-wise. I did run into two possible issues with it:
It looks like it would make multiple database hits if I was to do a third condition (union seems to take an IEnumerable as its parameter) - I was hoping to build up multiple AND and OR statements in code and then execute one request.
Union is not supported by ADO.Net Data Services (very disappointing)
Is what you want as simple as:
var people = from p in Person
where p.age < 18 || p.firstName == "Daniel"
select p;
or have you just given a simple example?
In which case you can use:
var under18 = from p in Person
where p.age < 18
select p;
var daniels = from p in Person
where p.firstName == "Daniel"
select p;
var combined = under18.Union(daniels);
LinqToSql may be intelligent enough to convert that to an OR but I'm not so sure.
What about using PredicateBuilder by Joe Albahari?
var predicate = PredicateBuilder.False<Person>();
predicate = predicate.Or(p => p.age < 18);
predicate = predicate.Or(p => p.firstName == "Daniel");
var query = Person.Where(predicate);
The predicate option is the way to go. The Union option DOES NOT build good sql. Reference http://social.msdn.microsoft.com/forums/en-US/linqprojectgeneral/thread/925b245d-5529-4a64-8cd4-4bc83ee6fe7a/
I wrote about how to achieve queries which search for a key value within a set on my blog .
Here are the relevant links.
Contains Operations in ADO.NET Data Services Part I
Contains Operations in ADO.NET Data Services Part II
Using this , you can write queries which look like this
//The set in which we have to search for a match
List<string> citiesIWillVisit = new List<string>() {"London","Berlin","Prague"};
var customersAround = nwContext.Customers
.IsIn<Customers>(citiesIWillVisit, c=> c.City);
foreach (Customers localCustomer in customersAround) {
System.Console.WriteLine(localCustomer.ContactName);
}

Resources