I want to run this LINQ simple code to have record number in LINQ but result is beneath error
var model = _db2.Persons.Select(
(x, index) => new
{
rn = index + 1,
col1 = x.Id
}).ToList();
Error:
LINQ to Entities does not recognize the method
'System.Linq.IQueryable1[<>f__AnonymousType22
[System.Int32,System.Int32]] Select[Person,<>f__AnonymousType22](System.Linq.IQueryable1
[MvcApplication27.Models.Person], System.Linq.Expressions.Expression1[System.Func3
[MvcApplication27.Models.Person,System.Int32,<>f__AnonymousType2`2
[System.Int32,System.Int32]]])' method, and this method cannot be translated into a store
expression.
The problem is that LINQ to Entities doesn't understand how to convert that Select overload (the one that gives you the index) into a SQL query. You can fix this by first selecting the portion from the DB you need (to avoid selecting every column unnecessarily), then doing AsEnumerable() to take it as an IEnumerable<T> instead of an IQueryable<T>, and then doing the Select purely in C# (in short, IQueryable<T>s are converted to SQL, while IEnumerable<T>s are run in code).
var model = _db2.Persons.Select(x => x.Id).AsEnumerable().Select(
(id, index) => new
{
rn = index + 1,
col1 = id
}).ToList();
Note that the query as you have it appears to be unordered, so the id/index pairings can change each time you call this. If you expected consistency, you should order by something (e.g. _db2.Persons.OrderBy(...)).
Edit
Adding comment from Scott:
As a nice reference here is the list of all Linq statements built in
to the framework and a listing if it is compatible or not.
You could just select the Id and after it create your own anonymous object using linq to objects, for sample:
var model = _db2.Persons.Select(x => x.Id)
.ToList() // return int[]
.Select((id, index) => new
{
rn = index + 1,
col1 = id
}) // return anonymous[] (with rn and col1)
.AsEnumerable(); // get an IEnumerable (readonly collection)
Problably this is happen because Entity Framework does not support this kind of query using linq as linq could do in memory, so, in this case, you could select just you need (id in your case) and execute it, using ToList() method to concretize your query and after that you will have a list on memory, so, you can use linq to objects and use the supported method as you want.
Related
The challenge is about converting from method chain to standard linq a piece of code full of group by.
The context
To fully understand the topic here you can read the original question (with class definitions, sample data and so on): Linq: rebuild hierarchical data from the flattened list
Thanks to #Akash Kava, I've found the solution to my problem.
Chain method formulation
var macroTabs = flattenedList
.GroupBy(x => x.IDMacroTab)
.Select((x) => new MacroTab
{
IDMacroTab = x.Key,
Tabs = x.GroupBy(t => t.IDTab)
.Select(tx => new Tab {
IDTab = tx.Key,
Slots = tx.Select(s => new Slot {
IDSlot = s.IDSlot
}).ToList()
}).ToList()
}).ToList();
But, for sake of knowledge, I've tried to convert the method chain to the standard Linq formulation but something is wrong.
What happens is similar to this..
My attempt to convert it to Linq standard syntax
var antiflatten = flattenedList
.GroupBy(x => x.IDMacroTab)
.Select(grouping => new MacroTab
{
IDMacroTab = grouping.Key,
Tabs = (from t in grouping
group grouping by t.IDTab
into group_tx
select new Tab
{
IDTab = group_tx.Key,
Slots = (from s in group_tx
from s1 in s
select new Slot
{
IDSlot = s1.IDSlot
}).ToList()
}).ToList()
});
The result in LinqPad
The classes and the sample data on NetFiddle:
https://dotnetfiddle.net/8mF1qI
This challenge helped me to understand what exactly returns a Linq Group By (and how prolix is the Linq syntax with Group By).
As LinqPad clearly shows a Group By returns a List of Groups. Group is a very simple class which has just one property: a Key
As this answer states, from definition of IGrouping (IGrouping<out TKey, out TElement> : IEnumerable<TElement>, IEnumerable) the only way to access to the content of the subgroups is to iterate through elements (a foreach, another group by, a select, ecc).
Here is shown the Linq syntax formulation of the method chain.
And here is the source code on Fiddle
But let's go on trying to see another solution:
What we usually do in SQL when we do a Group By is to list all the columns but the one which have been grouped. With Linq is different.. it still returns ALL the columns.
In this example we started with a dataset with 3 'columns' {IDMacroTab, IDTab, IDSlot}. We grouped for the first column, but Linq would return the whole dataset, unless we explicitly tell him..
I have a simple scenario.I want to list out all the employees except the logged in user.
Similar SQL Condition is
select * from employee where id not in(_loggedUserId)
How can I acheive the above using LINQ.I have tried the following query but not getting the desired list
int _loggedUserId = Convert.ToInt32(Session["LoggedUserId"]);
List<int> _empIds = _cmn.GetEmployeeCenterWise(_loggedUserId)
.Select(e => e.Id)
.Except(_loggedUserId)
.ToList();
Except expects argument of type IEnumerable<T>, not T, so it should be something like
_empIds = _cmn.GetEmployeeCenterWise(_loggedUserId)
.Select(e => e.Id)
.Except(new[] {_loggedUserId})
.ToList();
Also note, this is really redundant in the case when exclusion list contains only one item and can be replaces with something like .Where(x => x != _loggedUserId)
Why not use a very simple Where condition?
_empIds = _cmn.GetEmployeeCenterWise(_loggedUserId).Where(e=>e.Id != _loggedUserId).ToList();
The title of your question is how to perform a not in query against a database using LINQ. However, as others have pointed out your specific problem is better solved by a using users.Where(user => user.Id != loggedInUserId).
But there is still an answer on how to perform a query against a database using LINQ that results in NOT IN SQL being generated:
var userIdsToFilter = new[] { ... };
var filteredUsers = users.Where(user => !userIdsToFilter.Contains(user.Id));
That should generate the desired SQL using either Entity Framework or LINQ to SQL.
Entity Framework also allows you to use Except but then you will have to project the sequence to ID's before filtering them and if you need to original rows you need to fetch them again from the filtered sequence of ID's. So my advice is use Where with a Contains in the predicate.
Use LINQ without filtering. This will make your query execute much faster:
List<int> _empIds = _cmn.GetEmployeeCenterWise(_loggedUserId)
.Select(e => e.Id).ToList();
Now use List.Remove() to remove the logged-in user.
_empIds.Remove(_loggedUserId);
I`m trying to retrieve some data from a data range using the following code:
var rotas = db.X.Where(r => r.DataDaExecucao != null)
.Where(r => System.Data.Entity.DbFunctions.TruncateTime(r.Date.Value) >= System.Data.Entity.DbFunctions.TruncateTime(startDateTime))
.Where(r => System.Data.Entity.DbFunctions.TruncateTime(r.Date.Value) < System.Data.Entity.DbFunctions.TruncateTime(endDateTime))
.Join(db.T, r => r.Id, t => t.X_Id.Value,
(r, t) => new
{
id = r.Id,
start = r.Date.Value.ToString("s"),
end = r.Date.Value.AddDays(1).ToString("s"),
title = t.Z.Name,
allday = false
}).ToList();
"Date" properties are Nullable< DateTime>.
I`m getting the following error message:
LINQ to Entities does not recognize the method 'System.String ToString(System.String)' method, and this method cannot be translated into a store expression.
Exception Details: System.NotSupportedException: LINQ to Entities does not recognize the method 'System.String ToString(System.String)' method, and this method cannot be translated into a store expression.
Also, I don`t have the System.Data.Entity.dll assembly referenced in my csproj.
Ideas?
Thank you, in advance.
You can change the anonymous type using SqlFunctions where it will also generate the sql query.
In your case you use ToString("s"), meaning you want to get the date part of second that can be replaced by SqlFunctions::DatePart. And Date::AddDays can be replaced by SqlFunctions::DateAdd.
new
{
id = r.Id,
start = SqlFunctions.DatePart("s", r.Date),
end = SqlFunctions.DatePart("s", SqlFunctions.DateAdd("d", 1, r.Date)),
title = t.Z.Name,
allday = false
}
DateTime.ToString() cannot be converted into a SQL statement by LINQ to Entities. e.g.
start = r.Date.Value.ToString("s")
The thing to do is call .ToList() to force the LINQ to Entities to execute its underlying SQL query. That way the remainder of the LINQ statement will use LINQ to Objects (in-memory query of a collection of objects).
In your case I would break the LINQ statement into 2 parts:
The first half which queries the DB with LINQ to Entities SQL generation, and calls .ToList() at the end
The second half which runs LINQ to Objects to do the in-memory part.
Assuming following tables
Person
id
name
PersonTeam
id
person_id
is_supervisor
team_id
Team
id
TimeSheet
id
team_id
I would like to obtain all TimeSheets for a supervisor. I got name of supervisor, then I need select which team he is got supervisor role. Then select all time sheet of those teams.
I believe following query does
var allTimeSheets = ctx.PersonTeam.Where(y => y.Person.name == supervisor_name).Where(x => x.is_supervisor == true).Select(z => z.Team).Select(t => t.TimeSheet);
afer this operation I cannot understand allTimeSheets is a
IQueryable<ICollection<TimeSheet>>
I expected more a
<ICollection<TimeSheet>>
or any IEnumrable.
Then questions are :
why I got that kind of result ?
how to obtain TimeSheet[] where I got IQueryable < ICollection < TimeSheet > > ?
why did I get that kind of result ? I expected more a ICollection<TimeSheet>
An IQueryable<T> is an IEnumerable<T>. The reason it's returning an IQueryable is so you can chain other methods like OrderBy onto it and project those to the actual SQL.
I just realized what you're asking. To "flatten" the collection of collections, use SelectMany instead of two chained Selects:
var allTimeSheets = ctx.PersonTeam
.Where(y => y.Person.name == supervisor_name
&& y.is_supervisor == true)
.SelectMany(z => z.Team, (z, t) => t.TimeSheet);
The answer to your second question still applies:
how do I obtain a TimeSheet[] from a IQueryable<ICollection<TimeSheet>>
(first of all use the first part to change to an IQueryable<TimeSheet>)
You can call one of the "conversion" methods like ToArray, ToList, to "hydrate" the query into a concrete type.
You can also call "AsEnumerableto cast to anIEnumerableto convert the query to Linq-To-Objects, which has better support for custom functions in sorts, filters, etc. Note that callingAsEnunerable` does no immediately fetch the objects, but will do as as soon as the collection in enumerated.
I am using LINQ to create a list. But I want to use a function at the end to generate the object iself, something LINQ complains about
LINQ to Entities does not recognize the method 'WashroomStatusItem GetWashroomStatusForItem(WashroomStatus)' method, and this method cannot be translated into a store expression.
What am I doing wrong?
var query = (from c in context.WashroomStatus
where c.WashroomId == GroupItem.WashroomID
select GetWashroomStatusForItem(c));
private WashroomStatusItem GetWashroomStatusForItem(WashroomStatus item)
{
WashroomStatusItem temp = new WashroomMonitorWCF.WashroomStatusItem();
//do stuff with it
return temp;
}
The problem is that the SQL conversion can't convert your method into SQL. You should use AsEnumerable() to "switch" from the out-of-process provider to LINQ to Objects. For example:
var query = context.WashroomStatus
.Where(c => c.WashroomId == GroupItem.WashroomID)
.AsEnumerable()
.Select(c => GetWashroomStatusForItem(c));
Note that if GetWashroomStatusForItem only uses some properties, you may want to project to those separately first, to reduce the amount of information fetched from the server:
var query = context.WashroomStatus
.Where(c => c.WashroomId == GroupItem.WashroomID)
.Select(c => new { c.Location, c.Date };
.AsEnumerable()
.Select(p => GetWashroomStatusForItem(p.Location, p.Date));
Jon Skeet's answer is correct, but I'd add that depending on the nature of GetWashroomStatusForItem(), it should probably either be broken down into LINQ statements and added into the query itself, or it should be executed after the query has returned.
So, lets say GetWashroomStatusForItem() looks something like this: note that this is extremely oversimplified.
public static WashroomStatus GetWashroomStatusForItem(Item c)
{
return c.WashroomStatus;
}
it should just be added to the LINQ query like this:
var query = (from c in context.WashroomStatus
where c.WashroomId == GroupItem.WashroomID
select c.WashroomStatus);
But if it relies heavily on stuff not in the db, I'd just end the Linq statement before you get the WashroomStatus, and then call GetWashroomStatusForItem() on the results. It's not gonna a performance difference since Linq uses lazy evaluation, and you generally want to keep db operations separate from "programmatic" ones.