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);
Related
I am having difficulty understanding how Entity Framework generates a single SQL Query from a couple of Linq methods. Here is a code which selects Username from a table.
var result1 = context.UserMasters
.Where(t => t.UserRole == "LOCAL")
.Skip(100)
.Take(100)
.Select(t => new { t.UserName });
Typically the above code is identical to the below code.
var test = context.UserMasters.Where(t=> t.UserRole == "LOCAL");
test = test.Skip(100);
test = test.Take(100);
var result2 = test.Select(t => new { t.UserName });
I hope we can get results from the table after any Linq Method. So there is a list readily available always. Is it selecting all results from the table initially and doing operation on the list ?
If the type is IQueryable, then the filtering of data happens at the database side. But if the type of query is IEnumerable or other than IQueryable, all the data from the table is fetched and filtering is done at .Net side. It is always advised to use IQueryable in these cases. Please read about IQueryable and IEnumerable difference.
Background: I have two Collections of different types of objects with different name properties (both strings). Objects in Collection1 have a field called Name, objects in Collection2 have a field called Field.
I needed to compare these 2 properties, and get items from Collection1 where there is not a match in Collection2 based on that string property (Collection1 will always have a greater or equal number of items. All items should have a matching item by Name/Field in Collection2 when finished).
The question: I've found answers using Lists and they have helped me a little(for what it's worth, I'm using Collections). I did find this answer which appears to be working for me, however I would like to convert what I've done from query syntax (if that's what it's called?) to a LINQ query. See below:
//Query for results. This code is what I'm specifically trying to convert.
var result = (from item in Collection1
where !Collection2.Any(x => x.ColumnName == item.FieldName)
select item).ToList();
//** Remove items in result from Collection1**
//...
I'm really not at all familiar with either syntax (working on it), but I think I generally understand what this is doing. I'm struggling trying to convert this to LINQ syntax though and I'd like to learn both of these options rather than some sort of nested loop.
End goal after I remove the query results from Collection1: Collection1.Count == Collection2 and the following is true for each item in the collection: ItemFromCollection1.Name == SomeItemFromCollection2.Field (if that makes sense...)
You can convert this to LINQ methods like this:
var result = Collection1.Where(item => !Collection2.Any(x => x.ColumnName == item.FieldName))
.ToList();
Your first query is the opposite of what you asked for. It's finding records that don't have an equivalent. The following will return all records in Collection1 where there is an equivalent:
var results=Collection1.Where(c1=>!Collection2.Any(c2=>c2.Field==c1.Name));
Please note that this isn't the fastest approach, especially if there is a large number of records in collection2. You can find ways of speeding it up through HashSets or Lookups.
if you want to get a list of non duplicate values to be retained then do the following.
List<string> listNonDup = new List<String>{"6","1","2","4","6","5","1"};
var singles = listNonDup.GroupBy(n => n)
.Where(g => g.Count() == 1)
.Select(g => g.Key).ToList();
Yields: 2, 4, 5
if you want a list of all the duplicate values then you can do the opposite
var duplicatesxx = listNonDup.GroupBy(s => s)
.SelectMany(g => g.Skip(1)).ToList();
I am a beginner in EF and LINQ and I would like to retrieve a list of categories (with filter) by product id.
So, I have many-to-many relation between Product * <---> * Category and I use the following code:
var categList = dbContext.Products
.Where(prod => prod.PROD_UID == 1234)
.SelectMany(prod => prod.Categories)
.Distinct();
categList = SearchCategories(filter, categList);
categList = SortCategories(filter, categList);
categList = PageCategories(filter, categList);
where SearchCategories is used to reuse some code and looks like below
IQueryable<Category> SearchCategories(MyFilter filter, IQueryable<Category> source = null)
{
source = source ?? this.dbContext.Categories;
return source.Where(cat => [...filtering...] );
}
Although this looks ok, I would like to have it slightly optimized, with filtering inside the SelectMany (make use of SearchCategories inside SelectMany)... but I cannot make it work. I tried this, but gives me error
var categList = dbContext.Products
.Where(prod => prod.PROD_UID == 1234)
.SelectMany(cat => SearchCategories(filter, prod.Categories.AsQueryable()).AsEnumerable());
// throws LINQ to Entities does not recognize the method 'SearchCategories'
How could I filter the categories inside SelectMany?
Thank you!
Your problem is you are confusing the server query with the client query there is no magic here.
your first query until Distinct is serialized and sent to the server, then the server sends a response and you then run a filter in your client.
when you put the SearchCategories in the server query it cant be resolver so you get the error.
you have two options here:
1:Just write all your query from SearchCategories in the first query making it run in the server
.SelectMany(prod => prod.Categories.Where(c => [...filtering...]))
remember the filtering cant call client code.
2:You put a ToList or ToArray and then use the SearchCategories but this option wont optimize anything.
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.
Here is my query -
var data = Goaldata.GroupBy(c => c.GoalId).ToList();
This returns a Igrouping object and I want an Iqueryable object which I can directly query to get the data while in this case I have to loop through using a foreach() and then get the data. Is there another way to group by in LINQ which returns directly as a list of Iqueryable or a List as similar to what happens for order by in LINQ.
The easiest way is probably
var data = Goaldata.GroupBy(c => c.GoalId).SelectMany(c => c).ToList();
In the OO sense they aren't really grouped, but they are ordered with the groups together.
Whilst the accepted answer is correct, it seems to be unnecessarily complicated. Assuming GoalId is an int you can just use OrderBy:
var data = Goaldata.OrderBy(c => c.GoalId).ToList();
Or .GroupBy(c => c.GoalId).AsQueryable()...