I am passing a string list of studentKeys to my LINQ to Entities query.
So I want to return those data that are in that coming list.
public IQueryable<Students> GetStudentsFromKeys(List<string> studentKeys)
{
var result = from a in this.Context.Students
where // ?
return result.ToList();
}
But How should I actually write such a query? I want to query that table and if its keys are the same as one of the keys in that list, return it as a result.
You can do:
var result = from a in this.Context.Students
where studentKeys.Contains(a.StudentKey)
select a;
Or with method syntax as:
var query = this.Context.Students
.Where(r => studentKeys.Contains(r.StudentKey));
(assuming StudentKey is the name of the field you want to compare)
This would generate query similar to
SELECT * from Students WHERE StudentKey in ("1","2","3")
Related
I am trying to get data from linq in asp.net core. I have a table with a Position with a FacultyID field, how do I get it from the Position table with an existing userid. My query
var claimsIdentity = _httpContextAccessor.HttpContext.User.Identity as ClaimsIdentity;
var userId = claimsIdentity.FindFirst(ClaimTypes.NameIdentifier)?.Value.ToString();
var data = _context.Positions.Where(p => p.UserID.ToString() == userId).Select(x => x.FacultyID).???;
What can I add after the mark? to get the data. Thank you so much
There are several things you can do. An example in your case would be:
var data = _context.Positions.Where(p => p.UserID.ToString() == userId).Select(x => x.FacultyID).FirstOrDefault();
If you expect more than 1 results, then you would do:
var data = _context.Positions.Where(p => p.UserID.ToString() == userId).Select(x => x.FacultyID).ToList();
You have to be aware of the difference between a query and the result of a query.
The query does not represent the data itself, it represents the potential to fetch some data.
If you look closely to the LINQ methods, you will find there are two groups: the LINQ methods that return IQueryable<...> and the others.
The IQueryable methods don't execute the query. These functions are called lazy, they use deferred execution. You can find these terms in the remarks section of every LINQ method.
As long as you concatenate IQueryable LINQ methods, the query is not executed. It is not costly to concatenate LINQ methods in separate statements.
The query is executed as soon as you start enumerating the query. At its lowest level this is done using GetEnumerator and MoveNext / Current:
IQueryable<Customer> customers = ...; // Query not executed yet!
// execute the query and process the fetched data
using (IEnumerator<Customer> enumerator = customers.GetEnumerator())
{
while(enumerator.MoveNext())
{
// there is a Customer, it is in property Current:
Customer customer = enumerator.Current;
this.ProcessFetchedCustomer(customer);
}
}
This code, or something very similar is done when you use foreach, or one of the LINQ methods that don't return IQueryable<...>, like ToList, ToDictionary, FirstOrDefault, Sum, Any, ...
var data = dbContext.Positions
.Where(p => p.UserID.ToString() == userId)
.Select(x => x.FacultyID);
If you use your debugger, you will see that data is an IQueryable<Position>. You'll have to use one of the other LINQ methods to execute the query.
To get all Positions in the query:
List<Position> fetchedPositions result = data.ToList();
If you expect only one position:
Position fetchedPosition = data.FirstOrDefault();
If you want to know if there is any position at all:
if (positionAvailable = data.Any())
{
...
}
Be aware: if you use the IQueryable, the data will be fetched again from the DbContext. So if you want to do all three statements efficiently these, make sure you don't use the original data three times:
List<Position> fetchedPositions result = data.ToList();
Position firstPosition = fetchedPostion.FirstOrDefault();
if (firstPosition != null)
{
ProcessPosition(firstPosition);
}
I am trying to fetch a list of users after filtering by their name.
Query:
string filter="alex, faheem, Cohen";
var filterArr=filter.Split(new []{','},StringSplitOptions.RemoveEmptyEntries).Select(f=>f.Trim()).ToList();
var users= (from u in DbContext.Users
where filterArr.Any(y=> u.Name.Contains(y)) select u);
This gives me the error:
Local sequence cannot be used in LINQ to SQL implementations of query operators except the Contains operator.
I can't use filterArr.Contains(x.Name) because Name column contains both first name and second name. Just Like in list above their is an item "alex" and I have a name "Alex Hales" combined in Name column. So If I use filterArr.Contains(x.Name) it will not give me the result.
Any help will be much appreciated.
I'm not sure this is possible in a single statement like this. It's too complicated for the poor parsing stuff to work out.
However, you can get an IQueryable(), then iterate over your filters append these as individual WHERE clauses, then these should get added to the SQL properly later.
Something like this:
//this just gets a reference the DbSet, which implements IQueryable<User>
var queryable = _dbContext.Users;
//iterate over the filters and add each as a separate WHERE clause
foreach(var f in filters)
{
//this just adds to the existing expression tree..
queryable = queryable.Where(u=>u.Name.Contains(f));
}
//this will actually hit the database.
var results = queryable.ToList();
This should generate something like this in SQL (entirely pseudo-code)
select
u.*
from
users u
where
(u.username like "%Sue%")
or (u.username like "%Bob%")
Hope this helps...
I think you can do something like this
string filter = "alex, faheem, Cohen";
var filterArr = filter.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(f => f.Trim()).ToList();
var users = _dbContext.Users.Where(x => filterArr.Any(n => n.Contains(x.Name))).ToList();
UPDATE
For your requirement following query will work fine.
string filter = "Alex, faheem, Cohen";
var filterArr = filter.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).Select(f => f.Trim())
.ToList();
var users = _dbContext.Users
.Where(x => filterArr.Any(n => x.UserName.Contains(n))).ToList();
If user has searched for "alex" and in Name (database column) there is "Alex Hales". users query will return the user "Alex Hales".
I need to union these rows on two ids without using an IEqualityComparer, as those are not supported in LINQ to Entities.
In result I need every unique combination of BizId and BazId, with the value from foos if the id pair came from there, else the value should be zero. This is a greatly simplified example and in reality these tables are very large and these operations cannot be done in memory. Because of this, this query needs to work with LINQ to Entities so that it can be translated to valid SQL and execute on the database. I suspect this can be done with some combination of where, join, and DefaultIfEmpty() instead of the Union and Distinct() but I am at a loss for now.
var foos = from f in Context.Foos where f.isActive select new { BizId = f.bizId, BazId = f.BazId, Value = f.Value };
var bars = from b in Context.Bars where b.isEnabled select new { BizId = b.bizId, BazId = b.BazId, Value = 0 };
var result = foos.Union(bars).Distinct(); //I need this to compare only BizId and BazId
You can group by the two fields and then get the first item of each group:
foos.Union(bars).GroupBy(x => new { x.bizId, x.bazId })
.Select(g => g.FirstOrDefault())
I have a query as follows:
var paymentInfo =
from i in dbconnect.tblPayments
where i.tenderId == _tenderId
select i;
This query has some results, but I need to add an additional result that I already have, from the variable PaymentInfo.
For example suppose that my query has 2 results i need to add another result to "PaymentInfo" using linq.
I thought that the result is a kind of list, and that I could call .Add(PaymentInfo), but this doesn't work
How can I do this?
You can use Concat to concat another sequence to the end of this one.
var paymentInfo = paymentInfo.Concat(someOtherPayments);
I thought that the result is a kind of list
No, the result is an IEnumerable<T> which is read-only. You can create a list by calling .ToList() and then add an item to it.
var paymentInfo = (from i in dbconnect.tblPayments
where i.tenderId == _tenderId
select i).ToList();
paymentInfo.Add(existingPayment);
I have my query set up like so to allow for pagination. While this works, I have to basically run the same query twice to get the total matching results for the query AND allow for pagination. Is there any way to combine this into a single query?
public SearchResult GetResults()
{
//query is built elsewhere
var totalResults = (from i in Collection.Find(query)
select i).Count();
var results = (from i in Collection.Find(query)
select i)
.Skip(recordsToSkip)
.Take(recordsToTake)
.ToList();
//SearchResult is defined elsewhere
return new SearchResult
{
Results = results,
TotalResults = totalResults
};
}
First, to get the count you should not do a linq query and then count the results. This way enumerates all the results and then counts them, which is costly. You should instead use:
var totalResults = Collection.Find(query).Count()
This Count method is defined on the MongoCursor itself and will count the results in mongo, instead of in your .Net application.
I guess that was the real problem behind the question. But if you still want to unite the 2 queries you can do that like so:
var results = (from i in Collection.Find(query) select i).ToList();
var totalResults = results.Count();
var page = results
.Skip(recordsToSkip)
.Take(recordsToTake)
.ToList();
That will get the whole collection, count it, and return a page of it. I would not recommend you do that though, because you don't need the whole collection.
P.S: When you use Linq on the result of Find, it does the filtering in your application and not in the DB, so you should change your query to this one:
var results = Collection.Find(query)
.SetSkip(recordsToSkip)
.SetLimit(recordsToTake)
.ToList();