I have a list of products and I have included ProductMetadatas in the query like this:
var products = _dbContext.Set<Product>()Include(x=>x.Productmetadatas).
Where(x => x.CompanyId == LoggedInUser.CompanyId && x.Active).ToList();
Now, what I want to do is I want to filter the ProductMetadats according to the CompanyId, like
var products = _dbContext.Set<Product>()Include(x=>x.Productmetadatas).
Where(x => x.CompanyId == LoggedInUser.CompanyId && x.Active &&
x.ProductMetadatas.Where(pm => pm.CompanyId == LoggedInUser.CompanyId)).ToList();
How can I do it in a single query?
If you want all products that actually do match your current users companyId you have to change it to the following:
var products = _dbContext.Set<Product>()Include(x=>x.Productmetadatas).
Where(x => x.CompanyId == LoggedInUser.CompanyId && x.Active &&
x.ProductMetadatas.Any(pm => pm.CompanyId == LoggedInUser.CompanyId)).ToList();
As you can guess .Any() checks if any element in your list matches your LINQ expression and returns a boolean. With that your expression is valid.
Previously it could not work because .Where() returns a list of elements.
EDIT:
Alright as it was noted that you want to adjust the ProductMetdatas you can do the following:
Create an extension for IEnumerable<T>:
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach(T item in source)
action(item);
}
And then adjust your LINQ like this:
var products = _dbContext.Set<Product>()Include(x=>x.Productmetadatas).
Where(x => x.CompanyId == LoggedInUser.CompanyId && x.Active).
ForEach(x => x.ProductMetadatas = x.ProductMetadatas.
Where(pm => pm.CompanyId == LoggedInUser.CompanyId).ToList()).ToList();
Now you invoke a function on each element which filters the ProductMetadatas and sets the property of your product to the filtered ProductMetadatas.
You can use join to filter.
var result = (from tbl in _dbContext.Set<Product>()
join lst in ProductMetadatas on lst.CompanyID eqauls LogginInUSer.CompanyID
where tbl.CompanyId == LoggedInUser.CompanyId && tbl.Active
select tbl)
Related
var itemInventoryUpdate2 = db.ItemInventoryDatas
.Single(items => items.ItemId == item.ItemId );
Hi How can I convert above code so that I can pass to multiple arguments like it will select not just for Item Id but also for the location Id.
use AND operator.
var itemInventoryUpdate2 = db.ItemInventoryDatas.Single(items => items.ItemId == item.ItemId && items.LocationId == item.LocationId);
You can use boolean logical operators inside lambdas:
var itemInventoryUpdate2 = db.ItemInventoryDatas
.Single(items => items.ItemId == item.ItemId && items.LocationId == item.LocationId);
Also if you want to concatenate multiple AND conditions you can specify multiple Where clauses:
var itemInventoryUpdate2 = db.ItemInventoryDatas
.Where(items => items.ItemId == item.ItemId)
.Where(items => items.LocationId == item.LocationId)
.Single();
I inherited the LINQ query below and I feel that the query can be refactored for efficiency. The query currently takes about 6-8 seconds of processing time to return one record to the user on the front-end of the application. LINQ is not my strong suite, so any help would be greatly appreciated.
The query should ultimately produce a distinct list of CA_TASK_VW objects that are tied to a list of distinct CA_OBJECT_ID's obtained from the CA_OBJECT, CA_PEOPLE, and CA_CONTRACTOR tables.
var data = (from a in _db.CA_TASK_VW
where a.TASK_TYPE == "INSPECTION" && a.TASK_AVAILABLE_FLAG == "Y" && a.TARGET_END_DATE == null
select a).AsQueryable();
data = data.Join(_db.CA_OBJECT.Where(o => o.ENTERED_BY == _userId),
o => o.CA_OBJECT_ID, p => p.CA_OBJECT_ID,
(t, p) => t)
.Union(data.Join(_db.CA_PEOPLE.Where(p => p.EMAIL == _email),
t => t.CA_OBJECT_ID, p => p.CA_OBJECT_ID,
(t, p) => t))
.Union(data.Join(_db.CA_CONTRACTOR.Where(c => c.CONTRACTOR.EMAIL == _email),
t => t.CA_OBJECT_ID, c => c.CA_OBJECT_ID,
(t, c) => t));
The code seems to be using Join/Union to execute basically a where predicate on the list of CA_TASK_VW, filtering it step by step to the final result, so what happens if you just specify the where condition directly?
var data = from a in _db.CA_TASK_VW
where a.TASK_TYPE == "INSPECTION" && a.TASK_AVAILABLE_FLAG == "Y" && a.TARGET_END_DATE == null
select a;
data = data.Where(t => _db.CA_OBJECT.Where(o => o.ENTERED_BY == _userId).Select(o => o.CA_OBJECT_ID).Contains(t.CA_OBJECT_ID) ||
_db.CA_PEOPLE.Where(p => p.EMAIL == _email).Select(p => p.CA_OBJECT_ID).Contains(t.CA_OBJECT_ID) ||
_db.CA_CONTRACTOR.Where(c => c.CONTRACTOR.EMAIL == _email).Select(c => c.CA_OBJECT_ID).Contains(t.CA_OBJECT_ID));
You could try using UNION ALL if you don`t really care about duplicates in your query results as it works much faster than UNION
I have the following two tables which hold the information on items that have been completed I needed to do it this way for reporting purposes.
qry = db.AssemblyListItems
.AsNoTracking()
.Where(x => x.ProductionPlanID == (long)_currentPlan.ProductionPlan )
.ToList();
var _query = qry.Where(w => w.ItemCode == "EPR15CT.L01" && w.DocumentNo == "0000026590")
.SingleOrDefault();
var hasbeenAssembled = dbCompletedPrinteds
.AsNoTracking()
.Where(x => x.ProductionPlanId == (long)_currentPlan.ProductionPlan)
.ToList();
foreach (var item in hasbeenAssembled) {
qry.RemoveAll(X => X.SOPOrderReturnID == Int32.Parse(item.SopLineItemId) );
}
If it finds any matching items in the second table to remove it from the main query.
You will see the tables have much the same data stored in them. But for some reason the the items is still showing in the I need some way of looping the first query with the second query and removing the matching items from the qry object.
So steps I need to do is :
Loop completed and printed object remove any matching products with the same document number and item code and match the productplan id item and then remove it from the master AssemblyListItems query and then dispaly in a gui at the min its keeping the item in the list.
Edit 2
This would work but I dont think its very effiecent.
List<AssemblyListItems> _query = qry.ToList();
foreach (AssemblyListItems item in _query)
{
var hasbeenAssembled = db.CompletedPrinteds.AsNoTracking().Where(x => x.ProductionPlanId == item.ProductionPlanID).ToList();
foreach(var subitem in hasbeenAssembled )
{
if(item.ProductionPlanID ==subitem.ProductionPlanId && item.DocumentNo == subitem.DocumentNo && item.DocumentNo == subitem.DocumentNo)
{
qry.RemoveAll(x => x.ProductionPlanID == subitem.ProductionPlanId && x.DocumentNo == item.DocumentNo && x.ItemCode == subitem.StockCode);
}
}
}
Edit 3
To Show the items in the edmx
Last week I did query below using Left outer Join to get three group of data
var results = (from srs in srsEmps
join dest in destEmps on srs.EmpCode equals dest.EmpCode into dsNull
from dest in dsNull.DefaultIfEmpty()
select new { srs = srs, dest = dest }).ToList();
var Common = results.Where(x => (x.srs != null) && ( x.dest != null)).ToList();
var Deleted = results.Where(x => x.dest != null).ToList();
var NewlyAdded = results.Where(x => x.srs != null);
Something like this maybe?
//first get list of assembled/completed items with the _currentplan's ID:
var hasbeenAssembled =
dbCompletedPrinteds
.AsNoTracking()
.Where(x => x.ProductionPlanId == (long)_currentPlan.ProductionPlan)
//note: not sure of underlying DB technology here, but this .ToList() will
//typically cause a DB query to execute here.
.ToList();
//next, use that to filter the main query.
qry = db.AssemblyListItems
.AsNoTracking()
.Where(x =>
//Get current plan items
(x.ProductionPlanID == (long)_currentPlan.ProductionPlan)
//filter out items which are in the previous list of 'completed' ones
&& (!hasBeenAssembled.Any(hba => hba.SopLineItemId==x.SOPOrderReturnID))
)
.ToList();
//I don't have any idea what _query is for, it doesn't seem to be used for anything
//in this example...
var _query = qry.Where(w => w.ItemCode == "EPR15CT.L01" && w.DocumentNo == "0000026590")
.SingleOrDefault();
I have a long Linq Where clause that I would like to populate with a predicate list.
List<Expression<Func<Note, bool>>> filters = new List<Expression<Func<Note, bool>>>();
filters.Add(p => p.Title != null && p.Title.ToLower().Contains(searchString));
filters.Add(p => p.Notes != null && p.Notes.ToLower().Contains(searchString));
filters.Add(GlobalSearchUser((List < User > users = new List<User>() { p.user1, p.user2, p.user3, p.user4 }), searchString));
notes = dataAccess.GetList<Note>(pn => pn.ProjectVersionID == projectVersionID, filterExtensions.ToArray())
.Where(filters.ToArray()).Take(10).ToList();
However I'm getting this error:
cannot convert from 'System.Linq.Expressions.Expression<System.Func<project.Contracts.DTOs.Note,bool>>[]' to 'System.Func<project.Contracts.DTOs.Note,bool>'
Which is an error on the .where clause. Pulling out the .where compiles just fine.
I think great answer from Hogan can be simplified and shorten a bit by use of Any and All Linq methods.
To get items that fulfill all the conditions:
var resultAll = listOfItems.Where(p => filters.All(f => f(p)));
And to get the items that fulfill any condition:
var resultAny = listOfItems.Where(p => filters.Any(f => f(p)));
There are at least two errors in your code:
List<Expression<Func<Note, bool>>> filters = new List<Expression<Func<Note, bool>>>();
change it to
List<Func<Note, bool>> filters = new List<Func<Note, bool>>();
You don't need Expression trees here. You are using IEnumerable<>, not IQueryable<>
notes = dataAccess.GetList<Note>(pn => pn.ProjectVersionID == projectVersionID, filterExtensions.ToArray())
.Where(filters.ToArray()).Take(10).ToList();
There .Where() accepts a single predicate at a time. You could:
notes = dataAccess.GetList<Note>(pn => pn.ProjectVersionID == projectVersionID, filterExtensions.ToArray())
.Where(x => filters.All(x)).Take(10).ToList();
or various other solutions, like:
var notesEnu = dataAccess.GetList<Note>(pn => pn.ProjectVersionID == projectVersionID, filterExtensions.ToArray())
.AsEnumerable();
foreach (var filter in filters)
{
notesEmu = notesEmu.Where(filter);
}
notes = notesEnu.Take(10).ToList();
Because all the .Where() conditions are implicitly in &&.
You have to loop over your filters and run a test on each one.
You can do it with linq like this to return true if any of your filters are true:
.Where(p => { foreach(f in filters) if (f(p) == true) return(true); return(false)})
or like this to to return true if all of your filters are true:
.Where(p => { foreach(f in filters) if (f(p) == false) return(false); return(true)})
You can't just pass an array of predicates to the where method. You need to either iterate over the array and keep calling Where() for each expression in the array, or find a way to merge them all together into one expression and use that. You'll want to use LinqKit if you go the second route.
I have IQuerable<MyEntity> and filters(conditions list), that i want to apply to my query.
Schematically I want to get looks like
//First filter group // Second filter group
QUERY = from MYTABLE where ( Name = "User" and Age = 19 ) OR ( Name = "Alex", and Age > 20 )
query = (query.Where(x => x.Name == value)
.Where(x => x.Age == value)
.Where(x => x.Post == value))
OR (
(query.Where(x => x.Name == value)
.Where(x => x.RegistrationDate == value))
I need to create IQuerable, that will contain result first and second filter group(IQuerable).
But, I can't execute at first 1-st filter group, then 2-nd group and concat results, because after appling my filters I must to do a few operations with IQuarable.
I tried create queryes and query.Concat() with main, but NHibernate does not support this method
public static IQueryable<IDevice> ApplyGroups(this IQueryable<IDevice> query, IList<ITerminalGroup> groups)
{
foreach (ITerminalGroup group in groups)
{
IQueryable<IDevice> groupQuery = query.AsQueryable();
// apply to groupQuery conditions
groupQuery = groupQuery.ApplyGroup(group);
query = query.Concat(groupQuery);
}
return query;
}
static IQueryable<IDevice> ApplyGroup(this IQueryable<IDevice> query, ITerminalGroup group)
{
foreach (ITermGroupCondition condition in group.Conditions)
{
query = query.Where(x => x.SpecialAttributes.Any(sa => x.Id == condition.AttribId && sa.AttribValue.Equals(condition.Value)));
}
return query;
}
Count of conditions may be different, I do not know it in advance
How to combine LINQ conditions in group with OR operator ?
You can use PredicateBuilder to do that; combine the conditions with the PredicateBuilder.Or method, and pass the resulting condition to the Where method.