Suppose I have a list of employees and each employee has several projects. I can get a given employee using:
var employee = employees.SingleOrDefault(x => x.Id == "id");
But how can I filter also project for the employee?
For example:
var employee = list
.SingleOrDefault(x => x.Key == employeeKey &&
x.Projects.SingleOrDefault(p => p.Key == projectKey));
If you want to filter down the Projects after getting the Employee you can use a .Select().
var result = employees.Where(e => e.Id == id).Select(e => new Employee
{
Id = e.Id,
Projects = e.Projects.SingleOrDefault(p => p.Key == projectKey)
}).SingleOrDefault();
So you can get the data you need in one step, but you have to assign the properties by yourself.
Another way is to first get your Employee and then filter down the projects, like BoredomOverload suggested:
var employee = employees.SingleOrDefault(x => x.Id== "id");
employee.Projects = employee.Projects.SingleOrDefault(p => p.Key == projectKey);
Either way you get the employee and the Projects of that Employee filtered.
var employee = employees.SingleOrDefault(
x => x.Id.Equals("id") && x.project.Equals("project")
);
Use Any() LINQ method like
var employee = employees.SingleOrDefault(x => x.Id== "id" && x.Projects.Any(p => p.Id == "Id"));
Moreover, You are filtering based on employee ID x.Id== "id" and mostly that employee ID would a primary key (Unique in nature) and in such case filtering just by Id would be much enough I believe
SingleOrDefault returns the object if found or null. So, in your case, it returns all employees because you are not testing anything. You just said if the project is there then return it.
Use Any instead which will return a boolean value if exist or not:
var employee = list.SingleOrDefault(x => x.Key == customerKey && x.Projects.Any(p => p.Key == projectKey));
If you need to filter if he has only one project with the specific key:
var employee = list.SingleOrDefault(x => x.Key == customerKey && x.Projects.Count(p => p.Key == projectKey) == 1);
You can also achieve it with SingleOrDefault but test the value with null:
var employee = list.SingleOrDefault(x => x.Key == customerKey && x.Projects.SingleOrDefault(p => p.Key == projectKey) != null);
If you want the return type to be more specific then use the select.
If it didn't work, try to add "include" to the list:
list.Include("Projects").... the rest of the query
Related
I have used this to pick just a single column from the collection but it doesn't and throws casting error.
ClientsDAL ClientsDAL = new DAL.ClientsDAL();
var clientsCollection= ClientsDAL.GetClientsCollection();
var projectNum = clientsCollection.Where(p => p.ID == edit.Clients_ID).Select(p => p.ProjectNo).ToString();
Method:
public IEnumerable<Clients> GetClientsCollection(string name = "")
{
IEnumerable<Clients> ClientsCollection;
var query = uow.ClientsRepository.GetQueryable().AsQueryable();
if (!string.IsNullOrEmpty(name))
{
query = query.Where(x => x.Name.Contains(name));
}
ClientsCollection = (IEnumerable<Clients>)query;
return ClientsCollection;
}
As DevilSuichiro said in comments you should not cast to IEnumerable<T> just call .AsEnumerable() it will keep laziness.
But in your case it looks like you do not need that at all because First or FirstOrDefault work with IQueryable too.
To get a single field use this code
clientsCollection
.Where(p => p.ID == edit.Clients_ID)
.Select(p => p.ProjectNo)
.First() // if you sure that at least one item exists
Or (more safe)
var projectNum = clientsCollection
.Where(p => p.ID == edit.Clients_ID)
.Select(p => (int?)p.ProjectNo)
.FirstOrDefault();
if (projectNum != null)
{
// you find that number
}
else
{
// there is no item with such edit.Clients_ID
}
Or even simpler with null propagation
var projectNum = clientsCollection
.FirstOrDefault(p => p.ID == edit.Clients_ID)?.ProjectNo;
I want to get all the Pre_Number where all Reconcile_Status related to that Pre_Number=null. In this case there should not be any item in list.If there would be some other Pre_number for eg. 7/2018 and it has two records and Reconcile_Status for those records is NULL then i should get one item in list that is 7/2018.
I tried
var NoNReconciled = context.tbl_prerelease_invoice
.Where(x => x.Reconcile_Status==null)
.Select(y => new { y.Pre_number }).Distinct().ToList();
But i got 6/2018
Well, your current attempt only checks that there is at least one record where Reconcile_Status is null, but it doesn't check that there are no records with the same Pre_number where Reconcile_Status is not null.
This should do the trick:
var NoNReconciled = context.tbl_prerelease_invoice
.Where(x => x.Reconcile_Status == null &&
!context.tbl_prerelease_invoice
.Any(y => y.Pre_number == x.Pre_number && y.Reconcile_Status != null)
).Select(y => new { y.Pre_number })
.Distinct().ToList();
No need to create anonymous object for Pre_Number. Try below code
var NoNReconciled = context.tbl_prerelease_invoice
.Where(x => x.Reconcile_Status==null)
.Select(y => y.Pre_number).Distinct().ToList();
Try this-
context.tbl_prerelease_invoice.GroupBy(r => r.Pre_number).Where(kv => kv.All(r => r.Reconcile_Status==null)).Select(kv => kv.Key).ToList();
I would like to order a Listview based on the products'name it displays. My website is made of several languages and thus I built a linked table with a product name for each languages.
When I try to sort it I always get this error
DbSortClause expressions must have a type that is order comparable.
Parameter name: key
My code is the following:
IQueryable<Product> query = from p in _dbCtx.Products
where p.LanguageProduct.Any(lg => lg.Language == _currentCulture)
select p;
...
if (keys.Contains("OrderBy"))
{
if (Request.QueryString["OrderBy"] == "NameAsc")
query = query.OrderBy(t => t.LanguageProduct.Select(v => v.ProductName));
}
Any suggestions? Many thanks in advance.
EDIT: Maybe I haven't been clear enough. Therefore, I'll add some more code:
IQueryable<Product> query = from p in _dbCtx.Products
where p.IsVisible == true
where p.LanguageProduct.Any(lg => lg.Language == _currentCulture)
select p;
if (keys.Contains("Indiv"))
{
if (Request.QueryString["Indiv"] == "IndivYes")
query = query.Where(c => c.IsCustomizable == true);
if (Request.QueryString["Indiv"] == "IndivNo")
query = query.Where(c => c.IsCustomizable == false);
}
if (keys.Contains("OrderBy"))
{
if (Request.QueryString["OrderBy"] == "NameAsc")
query = query.OrderBy(t => t.LanguageProduct.Select(v => v.ProductName));
else if (Request.QueryString["OrderBy"] == "NameDes")
query = query.OrderByDescending(t => t.LanguageProduct.Select(v => v.ProductName));
else if (Request.QueryString["OrderBy"] == "PriceAsc")
query = query.OrderBy(t => t.ListPrice);
else if (Request.QueryString["OrderBy"] == "PriceDes")
query = query.OrderByDescending(t => t.ListPrice);
}
Everything works fine by adding successive where clauses to my query until it has to order by name. Hereunder is the structure of my database:
table: Product ProductTranslation
columns: id ReferenceName FKId Language ProductName
Example: 1 FirstProduct 1 fr-FR Produit 1
1 de-DE Produkt 1
1 en-US Product 1
You can do this using this:
var queryable = query.SelectMany(p => p.LanguageProduct, (p, l) => new{p,l})
.OrderBy(t => t.l.ProductName)
.Select(t => t.p);
What I would like to do is to find the first or default value of the role Name given the Id.
Here is the LINQ I tried:
var roleId = await db.AspNetRoles
.Select(r => r.Id)
.Where(r => r.)
.FirstOrDefault();
Here is my class:
I have this class in Entity Framework Asp.Net Identity
public AspNetRole()
{
this.AspNetUsers = new List<AspNetUser>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<AspNetUser> AspNetUsers { get; set; }
When I look at what options I have after the r. I find that I cannot put in a name like r.Name
Can someone show me what I am doing wrong?
Because the Select projects the source onto a new mapping, in this case only containing the int Id. From there on you'll be operating on an IEnumerable<int>, which don't have a Name property.
You could use:
.Select(r => new { r.Id, r.Name })
To project into an anonymous object only containing Id and Name.
Alternatively you can query first, then project:
await db.AspNetRoles
.Where(r => r.Id == someId)
.Select(r => r.Name)
.FirstOrDefault();
Or omit the projection (the .Select() call) entirely, but it all depends on what you want to do with the results.
You have to Change the order of the execution to
var roleId = await db.AspNetRoles
.Where(r => r.Name = "your Name")
.Select(r => r.Id)
.FirstOrDefault();
The Problem in your code is that you Select the Id which is of type int. Then when you call Where you have a list of ints available. If you swap where and select you first filter on AspNetRoles then select the int.
Your issue makes perfect sense:). The problem is you are projecting before filtering. After the select you'll get a collection of ints. What you need to do is revers the query like so :
var roleId = await db.AspNetRoles
.Where(r => r.Name=%smething%)
.Select(r => r.Id)
.FirstOrDefault();
I hope this helps :)
Try this:-
var roleId = await db.AspNetRoles
.Where(r => r.Id == YourId)
.Select(x => x.Name)
.FirstOrDefault();
Or (If you are sure You have that Id):-
var roleId = await db.AspNetRoles.FirstOrDefault(x => x.Id == YourId).Name;
But, Please note it will throw Null Reference Exception if no id matches :)
Just change the order like so:
var roleId = await db.AspNetRoles
.Where(r => r.Id == 24)
.Select(s => s.Name)
.FirstOrDefault():
You select r.Id in your select so the result only contains the Ids. You could also do it like this:
var role = await db.AspNetRoles.FirstOrDefault(r => r.Name == "Some name");
if (role != null)
{
// more code about role.Id
}
I have the following linq:
objfl = db.tblFl.First(t => t.sp == id && t.ProgID == sPgm);
I like to also order by id but not sure how to do this. I tried a number of different ways but was not successful
As suggested by BrokenGlass, if you want to filter by ProgID, sort by sp and retrieve the first item:
db.tblFl.Where(t => t.ProgID == sPgm)
.OrderBy(t => t.sp)
.First()
Try this
objfl = db.tblFl.Where(t => t.sp == id && t.ProgID == sPgm).OrderBy(t => t.sp);