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();
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;
As shown in the below code, the API will hit the database two times to perform two Linq Query. Can't I perform the action which I shown below by hitting the database only once?
var IsMailIdAlreadyExist = _Context.UserProfile.Any(e => e.Email == myModelUserProfile.Email);
var IsUserNameAlreadyExist = _Context.UserProfile.Any(x => x.Username == myModelUserProfile.Username);
In order to make one request to database you could first filter for only relevant values and then check again for specific values in the query result:
var selection = _Context.UserProfile
.Where(e => e.Email == myModelUserProfile.Email || e.Username == myModelUserProfile.Username)
.ToList();
var IsMailIdAlreadyExist = selection.Any(x => x.Email == myModelUserProfile.Email);
var IsUserNameAlreadyExist = selection.Any(x => x.Username == myModelUserProfile.Username);
The .ToList() call here will execute the query on database once and return relevant values
Start with
var matches = _Context
.UserProfile
.Where(e => e.Email == myModelUserProfile.Email)
.Select(e => false)
.Take(1)
.Concat(
_Context
.UserProfile
.Where(x => x.Username == myModelUserProfile.Username)
.Select(e => true)
.Take(1)
).ToList();
This gets enough information to distinguish between the four possibilities (no match, email match, username match, both match) with a single query that doesn't return more than two rows at most, and doesn't retrieve unused information. Hence about as small as such a query can be.
With this done:
bool isMailIdAlreadyExist = matches.Any(m => !m);
bool isUserNameAlreadyExist = matches.LastOrDefault();
It's possible with a little hack, which is grouping by a constant:
var presenceData = _Context.UserProfile.GroupBy(x => 0)
.Select(g => new
{
IsMailIdAlreadyExist = g.Any(x => x.Email == myModelUserProfile.Email),
IsUserNameAlreadyExist = g.Any(x => x.Username == myModelUserProfile.Username),
}).First();
The grouping gives you access to 1 group containing all UserProfiles that you can access as often as you want in one query.
Not that I would recommend it just like that. The code is not self-explanatory and to me it seems a premature optimization.
You can do it all in one line, using ValueTuple and LINQ's .Aggregate() method:
(IsMailIdAlreadyExist, IsUserNameAlreadyExist) = _context.UserProfile.Aggregate((Email:false, Username:false), (n, o) => (n.Email || (o.Email == myModelUserProfile.Email ? true : false), n.Username || (o.Username == myModelUserProfile.Username ? true : false)));
I have the following Entity Framework function that it joining a table to a list. Each item in serviceSuburbList contains two ints, ServiceId and SuburbId.
public List<SearchResults> GetSearchResultsList(List<ServiceSuburbPair> serviceSuburbList)
{
var srtList = new List<SearchResults>();
srtList = DataContext.Set<SearchResults>()
.AsEnumerable()
.Where(x => serviceSuburbList.Any(m => m.ServiceId == x.ServiceId &&
m.SuburbId == x.SuburbId))
.ToList();
return srtList;
}
Obviously that AsEnumerable is killing my performance. I'm unsure of another way to do this. Basically, I have my SearchResults table and I want to find records that match serviceSuburbList.
If serviceSuburbList's length is not big, you can make several Unions:
var table = DataContext.Set<SearchResults>();
IQuerable<SearchResults> query = null;
foreach(var y in serviceSuburbList)
{
var temp = table.Where(x => x.ServiceId == y.ServiceId && x.SuburbId == y.SuburbId);
query = query == null ? temp : query.Union(temp);
}
var srtList = query.ToList();
Another solution - to use Z.EntityFramework.Plus.EF6 library:
var srtList = serviceSuburbList.Select(y =>
ctx.Customer.DeferredFirstOrDefault(
x => x.ServiceId == y.ServiceId && x.SuburbId == y.SuburbId
).FutureValue()
).ToList().Select(x => x.Value).Where(x => x != null).ToList();
//all queries together as a batch will be sent to database
//when first time .Value property will be requested
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);
I have the following two statements :-
var isadminByuser = tms.SecurityRoles.Where(a => a.Name.ToLower() == "administrator")
.Select(a=>a.SecurityRoleUsers.Where(a2 => a2.UserName.ToLower() == user.ToLower()));
if (isadminByuser.Count() >= 1) { return true;}
&
var adminByGroup = tms.SecurityRoles.Where(a => a.Name == "Administrator")
.SingleOrDefault().Groups
.Select(a2 => a2.TMSUserGroups
.Where(a3 => a3.UserName.ToLower() == user.ToLower()));
bool isadminByGroup = adminByGroup.Count() >= 1;
The first var isadminByuser will always have elements (will always be >=1), even if the where clause a3.UserName.ToLower() == user.ToLower())) is false, while the other var will have a count of zero is the where clause (a3.UserName.ToLower() == user.ToLower())) is false. So why will the first var never have a count of zero?
Thanks
The answer to the question asked is that you are selecting an IQueryable<SecurityRoleUsers> when you select
a.SecurityRoleUsers.Where(a2 => a2.UserName.ToLower() == user.ToLower())
which may or may not have a count of 0, but the containing query will return one of these IQueryables for each SecurityRole that matches Name = "administrator", hence the count will always be 1+ if there is at least one matching SecurityRole
Update:
// first get SecurityRoles
bool isadminByuser = tms.SecurityRoles.Where(a => a.Name.ToLower() == "administrator")
// now you're only interested in the related SecurityRoleUsers
.SelectMany( a => a.SecurityRoleUsers )
// now check if any of the SecurityRoleUsers meet your criteria
.Any( sru => sru.UserName.ToLower() == user.ToLower() );
Could you observe sql query differences from ms-sql-profiler
tms.SecurityRoles.Where(a => a.Name.ToLower() == "administrator")
.Select(a=>a.SecurityRoleUsers.Where(a2 => a2.UserName.ToLower() == user.ToLower()));
***
tms.SecurityRoles.Select(a=>a.SecurityRoleUsers.Where(a2 => a2.UserName.ToLower() == user.ToLower())).Where(a => a.Name.ToLower() == "administrator");