How can I do a select in linq to entities to select rows with keys from a list? Something like this:
var orderKeys = new int[] { 1, 12, 306, 284, 50047};
var orders = (from order in context.Orders
where (order.Key in orderKeys)
select order).ToList();
Assert.AreEqual(orderKeys.Count, orders.Count);
I tried using the Contains method as mentioned in some of the answers but it does not work and throws this exception:
LINQ to Entities does not recognize the method 'Boolean Contains[Int32](System.Collections.Generic.IEnumerable`1[System.Int32], Int32)' method, and this method cannot be translated into a store expression.
Try this:
var orderKeys = new int[] { 1, 12, 306, 284, 50047};
var orders = (from order in context.Orders
where orderKeys.Contains(order.Key);
select order).ToList();
Assert.AreEqual(orderKeys.Count, orders.Count);
Edit: I have found some workarounds for this issue - please see WHERE IN clause?:
The Entity Framework does not
currently support collection-valued
parameters ('statusesToFind' in your
example). To work around this
restriction, you can manually
construct an expression given a
sequence of values using the following
utility method:
I had the same problem and i solved like this
var orderKeys = new int[] { 1, 12, 306, 284, 50047};
var orders = (from order in context.Orders
where (orderKeys.Contains(order.Key))
select order).ToList();
Assert.AreEqual(orderKeys.Count, orders.Count);
Unfortunately the EF can't translate the queries others have suggested. So while those queries would work in LINQ to Objects, they won't work in LINQ to Entities.
So the solution is a little more involved.
However I have a blog post on this exact topic here. Essentially the solution is to use a little expression tree magic to build an big OR expression.
Hope this helps
Alex
Related
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();
Why does one method work but not the other, when it seems they are both doing the same thing, i.e. constructing an entity. My question then, is there a way to construct the entity in a L2E query instead of having to use just Linq or indeed both?
This works fine...
var queryToList = (from ac in ctx.AuthorisationChecks
where wedNumbers.Contains(ac.WedNo)
orderby ac.WedNo, ac.ExpAuthDate, ac.ActAuthDate
select new AuthorisationCheck
{
Blah = ac.Blah
}).ToList();
model.AuthorisationChecks = queryToList.Select(x => new AuthorisationCheck
{
Blah = x.Blah
}).ToList();
However, if i change...
var queryToList
to
model.AuthorisationChecks queryToList // Of type List<AuthorisationCheck>
i get the error in the Title...
The entity or complex type 'Model.AuthorisationCheck' cannot be constructed in a LINQ to Entities query.
EDIT:
In the model it is simply, nothing fancy here.
public List<AuthorisationCheck> AuthorisationChecks { get; set; }
EDIT2:
Tidied this up a little to be (which works fine)...
model.AuthorisationChecks = (from ac in ctx.AuthorisationChecks
where wedNumbers.Contains(ac.WedNo)
orderby ac.WedNo, ac.ExpAuthDate, ac.ActAuthDate
select ac).ToList()
.Select(x => new AuthorisationCheck
{
Blah = x.Blah
}).ToList();
EDIT2: My Solution
I wasn't happy with the anonymous type method and so went ahead and created a simple model containing only the properties I required to be used in the viewmodel.
Changed the type of model.AuthorisationChecks
from
List<AuthorisationCheck> // List of Entities
to
List<AuthorisationCheckModel> // List of models
which allows the following code to work, and without profiling it seems a lot quicker than using an anonymous type (and of course I don't cast to a list twice!).
model.AuthorisationChecks = (from ac in ctx.AuthorisationChecks
where wedNumbers.Contains(ac.WedNo)
orderby ac.WedNo, ac.ExpAuthDate, ac.ActAuthDate
select new AuthorisationCheckModel
{
Blah = x.Blah
}).ToList();
P.S. I was once warned by a coworker (who used to work for Microsoft) that it isn't a good idea to directly use Entities in this manner, maybe this was one of the reasons he was thinking of, I've also noticed some odd behavior using Entities directly in other cases (mainly corruptions).
Note: I generally use lambda expression instead of Fluent API, but the root issue should be the same.
I have historically noticed LINQ is unable to use C# classes for Select statements if the original datasource (i.e. ctx for you) is accessed by translating your query into SQL.
In other words, there are issues when getting something from the database and casting it to a custom class in the same chain.
LINQ is smart enough that it actually doesn't immediately execute your chained calls. It simply internally builds a query, and when you actually access your results (i.e. retrieve the value from memory), it executes the query.
I assume this is also the reason why you are faced with this error, because LINQ translates everything (including the Select) to SQL, and fails because there's no SQL-way to express it. In short, LINQ can't do a built query half-SQL, half-code. It's either all in SQL, or all in code.
You can usually confirm that this is the case by first making a List<> of the database table, then run the exact same query on it.
var myTable = db.AuthorizationCheck.ToList();
var myResult = myTable. //query here
Note: That is not a solution!
Taking the entire table in memory is an overly intensive way to work around this. It just proves the point that the problem isn't encountered if the datasource is in memory, but the error does occur if it's in a database.
There are ways I've fixed this, although I've never found a uniform way to approach this problem (generally depends on the opinion of my code reviewer, whether he likes the fix or not)
Using anonymous types, you can select what you want, and later cast it to the correct class. You can use the exact same fields, making a later cast easier to understand.
//Simpler query for clarity's sake
var myAnonymousResult = ctx.AuthorizationChecks
.Where(x => x.IsActive)
.Select(x => new { Name = x.Name, IsActive = x.IsActive })
.ToList();
var myCastResult = myAnonymousResult.Select(x => new Check() { Name = x.Name, IsActive = x.IsActive }).ToList();
If you use lambda expressions instead of the fluent API, you can call .ToList() after applying the filters but before calling the .Select() method. This ensures the current query will be executed, retrieved from the database, and put into an actual List<> in memory. At that point, you can call the .Select() statement without running into the same problem.
//Simpler query for clarity's sake
var myCastResult = ctx.AuthorizationChecks
.Where(x => x.IsActive)
.ToList()
.Select(x => new Check() { Name = x.Name, IsActive = x.IsActive });
Unfortunately though, my experience with this problem is anecdotal. I've never been able to officially confirm my suspicions as to the root cause of this issue; but the workarounds I mentioned should work as I've applied them numerous times in the past.
If anyone has an explanation of the root cause, I'd be very interested in hearing it!
If this query works fine:
var queryToList = (from ac in ctx.AuthorisationChecks
where wedNumbers.Contains(ac.WedNo)
orderby ac.WedNo, ac.ExpAuthDate, ac.ActAuthDate
select new AuthorisationCheck
{
Blah = ac.Blah
}).ToList();
then this should also work:
model.AuthorisationChecks = (from ac in ctx.AuthorisationChecks
where wedNumbers.Contains(ac.WedNo)
orderby ac.WedNo, ac.ExpAuthDate, ac.ActAuthDate
select new AuthorisationCheck
{
Blah = ac.Blah
}).ToList();
and in your first case you don't need to project again, you can directly assign it to model propeerty:
model.AuthorisationChecks = queryToList;
UPDATE:
As it is Linq To Entities,you have to do something like this using anonymous type:
var queryToList = (from ac in ctx.AuthorisationChecks
where wedNumbers.Contains(ac.WedNo)
orderby ac.WedNo, ac.ExpAuthDate, ac.ActAuthDate
select new
{
Blah = ac.Blah
}).ToList();
and then:
model.AuthorisationChecks = queryToList.Select(x => new AuthorisationCheck
{
Blah = x.Blah
}).ToList();
I have a sql statement like this:
DECLARE #destinations table(destinationId int)
INSERT INTO #destinations
VALUES (414),(416)
SELECT *
FROM GroupOrder grp (NOLOCK)
JOIN DestinationGroupItem destItem (NOLOCK)
ON destItem.GroupOrderId = grp.GroupOrderId
JOIN #destinations dests
ON destItem.DestinationId = dests.destinationId
WHERE OrderId = 5662
I am using entity framework and I am having a hard time getting this query into Linq. (The only reason I wrote the query above was to help me conceptualize what I was looking for.)
I have an IQueryable of GroupOrder entities and a List of integers that are my destinations.
After looking at this I realize that I can probably just do two joins (like my SQL query) and get to what I want.
But it seems a bit odd to do that because a GroupOrder object already has a list of DestinationGroupItem objects on it.
I am a bit confused how to use the Navigation property on the GroupOrder when I have an IQueryable listing of GroupOrders.
Also, if possible, I would like to do this in one trip to the database. (I think I could do a few foreach loops to get this done, but it would not be as efficient as a single IQueryable run to the database.)
NOTE: I prefer fluent linq syntax over the query linq syntax. But beggars can't be choosers so I will take whatever I can get.
If you already have the DestinationGroupItem as a Navigation-property, then you already have your SQL-JOIN equivalent - example. Load the related entities with Include. Use List's Contains extension method to see if the desired DestinationId(s) is(are) hit:
var destinations = new List<int> { 414, 416 };
var query = from order in GroupOrder.Include(o => o.DestinationGroupItem) // this is the join via the navigation property
where order.OrderId == 5662 && destinations.Contain(order.DestinationGroupItem.DestinationId)
select order;
// OR
var query = dataContext.GroupOrder
.Include(o => o.DestinationGroupItem)
.Where(order => order.OrderId == 5662 && destinations.Contain(order.DestinationGroupItem.DestinationId));
I have seen these StackOverflow Answers but they do not produce the same results when the filtering list is in memory.
I have a list of Ids. I want to remove any IDs that exists in the database, so that I am left with a list of IDs that need to be added. In other words, I need to perform a where not in SQL query, using Linq-To-Entities. The problem is, instead of producing that SQL, these methods each produce a SQL query per list item.
var providerIds = new [] {"1130", "1", "16"};
Method 1:
var missingProviders = (from provider in providerIds
where !JobProviders.Any(p => p.JobProviderID == provider)
select provider).ToList();
Method 2:
var missingProviders = (from provider in providerIds
where !(from p in JobProviders select p.JobProviderID).Contains(provider)
select provider).ToList();
Is there a way to structure the LINQ query such that it produces the intended not in form, or are these the only solutions?
What about something like
var providersInDb = (from provider in JobProviders
where providerIds.Contains(provider.JobProviderID)
select provider.JobProviderID).ToList();
var missingProviders = providerIds.Where(p => !providersInDb.Contains(p))
Tricky. I don't have my tools in front of me, so I don't know how this will pan out exactly.
var dbProviderIds = JobProviders.Select(p => p.JobProviderId);
var allProviders = dbProviderIds.Union(providerIds).Distinct();
var missing = allProviders.Except(dbProviderIds);
On the DB, get all the provider Ids, then combine that with the in-memory ones. Then remove the ones that are known on the database.
I am writing a LINQ query similar to the following:
var test = from o in dbcontext.Orders.AsEnumerable()
where o.ID==1
select new Order
{
Name = GetName(o.ID)
};
In order to call an external function within the LINQ query, I am using AsEnumerable() within the query.
I understand that normally the query is not executed until an enumeration function like ToList(), etc. is called. But here I am calling the enumeration within the query.
Can anyone tell me if it is considered bad practice to use AsEnumerable() like this? Will it suffer in performance compared to calling ToList() after creating the query?
I'd do
var ids = from o in dbcontext.Orders
where o.ID==1
select new { ID = o.ID };
var names = from i in ids.AsEnumerable()
select new Order { Name = GetName(i.ID) };
i.e. do as much querying as possible in the database, and then only perform the ID-to-name transformation in C#.