Linq filter after join - linq

I'm joining 4 different lists together in linq. I need to then do a filter before the select new. I'm having trouble figuring this out.
var results2 = from st in this
join currentGrowth in levels on new {st.Core, st.Grade } equals new {currentGrowth.Core, currentGrowth.Grade } into currentLevel
from level in currentLevel.Where(a => st.Score >= a.MinScore && st.Score <= a.MaxScore).DefaultIfEmpty()
join growthScores in ScoresGrowth on new { st.id, st.Core } equals new { growthScores.id, growthScores.Core } into gs
from gscores in gs.Where(a => !a.Passed && !st.Passed && a.TestName != st.TestName).DefaultIfEmpty()
join pastGrowth in levels on new { gscores?.Core, gscores?.Grade } equals new { pastGrowth?.Core, pastGrowth?.Grade } into pLevel
from pastLevel in pLevel.Where(a => gscores.Score >= a.MinScore && gscores.Score <= a.MaxScore).DefaultIfEmpty()
group new { st, gscores, level, pastLevel } by new { st.Division, st.School, st.Core }
into testGroups
select new
{
Division = testGroups.Key.Division,
Core = testGroups.Key.Core,
School = testGroups.Key.School,
All_Total = testGroups.Count(),
All_PassCount = testGroups.Count(a => a.st.Passed),
All_Growth = testGroups.Count(a=> !a.st.Passed && (a.level?.Level > a.pastLevel?.Level) )
};
I need the following filter applied to the fields retrieved in the select. Is there a way to do this before the select new, or must it be applied to every calculation in the select new. There are many more than are included here.
!(st.SOA_LEP && !st.Passed && pastLevel.Level < level.Level)
&& !(st.SOA_Transfer && !st.Passed && pastLevel.Level < level.Level)

Related

Left join times out on linq where right table is empty

I have a left join to perform . And take the entire objects from it . However it times out when the item collection is empty on doing .Select (x=>x.object) ;
public Tuple<td_GroupLicense, List<td_UserGroupMap>> ReturnActiveLicenseInfo(int GroupID)
{
Tuple<td_GroupLicense, List<td_UserGroupMap>> Tuple;
#endregion
var GroupUserLicense = from grp in Context.td_Groups
from lic in Context.td_GroupLicenses
.Where(x => grp.IdGroup == x.GroupID && x.GroupID == GroupID)
from ugm in Context.td_UserGroupMaps
.Where(x => grp.IdGroup == x.GroupID && x.GroupID == GroupID)
.DefaultIfEmpty()
select new { GL = lic, UGM = ugm };
td_GroupLicense License = GroupUserLicense.Select(x => x.GL).Distinct().SingleOrDefault();
List<td_UserGroupMap> UserMaps = GroupUserLicense.Select(x => x.UGM)
.OfType<td_UserGroupMap>()
.DefaultIfEmpty().ToList();
Tuple = new Tuple<td_GroupLicense, List<td_UserGroupMap>>(License, UserMaps);
return Tuple;
}
when I do the join then the line in
List<td_UserGroupMap> UserMaps = GroupUserLicense.Select(x => x.UGM)
.OfType<td_UserGroupMap>()
.DefaultIfEmpty().ToList();
times out since the collection UGM in GroupUserLicense is null . It cannot do the operation . I want to put the left join result of License and Usegroupmaps into the corresponding objects . But the Right table is null so the timeout occurs . How to overcome that ? And why is it happening ?

Deep LINQ projections, how?

Let's say I have a model created with EF 4.0
User
Roles
Permissions
Each entity has a DeleteDate property.
I want to get a specific user (with Name =...) and have the tree filled with items where DeletedDate == null..
This must be done with anonymous type projection as result, but I don't know how to accomplish this with a hierachy deeper than 2..
This is what I already have:
public MyProjection MyCall(string givenName)
{
var result = from s in context.Users
where (s.Name == givenName &&
s.DeletedDate == null)
select new
{
s,
roles = from r in s.Roles
where r.DeletedDate == null
select r
};
var outcome = result.FirstOrDefault();
if (outcome != null)
{
var myProjection = new MyProjection()
{
User = outcome.s,
Roles = outcome.roles
};
return myProjection;
}
return null;
}
Depending on your structure you could do something like this:
var result = m.Users.Where(u => u.DeletedDate == null)
.Select( u => new
{
u,
roles = u.Roles.Where(r => r.DeletedDate == null)
.Select(r => new
{
r,
permissions = r.Permissions.Where(p => p.DeletedDate == null)
})
}).FirstOrDefault(item => item.u.Name == givenName);
If you retrieve with the following:
var result = from s in MyUsers
where s.DeletedDate == null
select new aUser{
Roles = (from r in s.Roles
where r.DeletedDate == null
select r).ToList()
};
And then create a TreeView:
TreeView treeView = new TreeView();
Then set the ItemsSource of the TreeView to the IEnumerable:
treeView.ItemsSource = result;
Then build a HierarchicalDataTemplate in your TreeView to represent your Lists (similar to this or for more in depth this), then voila!

multiple conditions Linq extended

I need to consider multiple conditions to get value.
i mean if all conditions true that must give me a filtered answer.
Or one of them is true,rest are false...
so i need to write all possibilities??
if(a&b&c&d) else if(a&b&c) else if(a&c&d) else if(b&c&d) else if(a&b) else if (a&c)...etc ?? :))) Is there a shorter way to do this?
public List<ProductReqNoDate> GetRequestsQuery(string departmant, int reqStateID, string firstDate, string lastDate, string productName)
{
var db = new requestDBEntities();
bool dp = !string.IsNullOrEmpty(departmant);
bool pr = !string.IsNullOrEmpty(productName);
bool tm = !string.IsNullOrEmpty(firstDate) && !string.IsNullOrEmpty(lastDate);
bool rs = reqStateID > 0 ? true : false;
var query = (from r in db.requests
select new ProductReqNoDate
{
departmant = r.departmant,
reqNo = r.reqNo,
reqDate = r.reqDate,
productName = (from p in db.products where p.reqNo == r.reqNo select p.productName).FirstOrDefault()
}).ToList();
if (dp & pr & tm & rs)
{
var rState = (from ta in db.reqStates
where ta.reqStateID == reqStateID && ta.isActive == true
select ta.reqNo).ToList();
var prName = (from p in db.products where p.productName.Contains(productName) select p.reqNo).ToList();
DateTime dtfirstDate = Convert.ToDateTime(firstDate);
DateTime dtlastDate = Convert.ToDateTime(lastDate);
return query.Where(
r => rState.Contains(r.reqNo) //find by Request State
&& r.departmant == departmant //find by Departmant
&& (r.reqDate >= dtfirstDate && r.reqDate <= dtlastDate) //find by Date
&& prName.Contains(r.reqNo) //Find By Product Name
).ToList();
}
else if (dp & pr & tm) { /*return query.Where(...} */}
else if (pr & tm & rs) { /*return query.Where(...} */}
else if (dp & pr && rs) { /*return query.Where(...} */}
else if (dp & pr) { /*return query.Where(...} */}
//else if ...etc
}
Just add one Where condition at a time
public List<ProductReqNoDate> GetRequestsQuery(string departmant, int reqStateID, string firstDate, string lastDate, string productName)
{
var db = new requestDBEntities();
bool dp = !string.IsNullOrEmpty(departmant);
bool pr = !string.IsNullOrEmpty(productName);
bool tm = !string.IsNullOrEmpty(firstDate) && !string.IsNullOrEmpty(lastDate);
bool rs = reqStateID > 0 ? true : false;
var query = (from r in db.requests
select new ProductReqNoDate
{
departmant = r.departmant,
reqNo = r.reqNo,
reqDate = r.reqDate,
productName = (from p in db.products where p.reqNo == r.reqNo select p.productName).FirstOrDefault()
}).AsQueryable(); //AsQueryable is not always needed, but it shouldn't hurt and I don't feel like checking for this example.
if (dp)
{
query = query.Where(q => /*condition*/);
}
if (pr)
{
query = query.Where(q => /*condition*/);
}
if (tm)
{
query = query.Where(q => /*condition*/);
}
if (rs)
{
query = query.Where(q => /*condition*/);
}
return query.ToList();
}
You can build an expression with Expression.And like:
private Expression<Func<Request, bool>> GetPredicate(FilterDto filter)
{
Expression<Func<Request, bool>> predicate = r => r.ID == r.ID;
if (filter.Department.HasValue)
predicate = predicate.And(r => r.Department == filter.Department.Value);
if (filter.FirstDate.HasValue)
predicate = predicate.And(r => (r.reqDate >= filter.FirstDate.Value));
if (filter.LastDate.HasValue)
predicate = predicate.And(r => (r.reqDate <= filter.LastDate.Value));
/* ... */
return predicate;
}
Note: I put r => r.ID == r.ID here as first expression, just to have an expression to start with. This snippet does not fully cover your code, but I think it is enough as an example.
Use the expression in return query.Where(expression).ToList().

LINQ in Business Layer paging / sorting gridview in User layer

I have a gridview in my user layer that uses a business layer method as its datasource, and I want the gridview to support paging and sorting. When I returned an Ienumerable from the method, it will bring back all of the data. If I use Take/Skip to bring back only a page's worth, the gridview doesn't realize that there are many pages of data.
When I change the Ienumerable to an IQueryable, the DataBind() fails because the data has already been disposed of. I think this problem has something to do with when the query actually executes and it may have to do with the filters I am applying to the query (see below).
User Layer Code:
grdSelectedQuestionaires.DataSource = assessment.FilteredAssessmentList(filter);
grdSelectedQuestionaires.DataBind(); <-- Fails - "Cannot access a disposed object"
Business Layer Code:
public IQueryable<Assessment> FilteredAssessmentList(AssessmentSearchFilter filter)
{
using (PAQcDataLayerDataContext dc = new PAQcDataLayerDataContext())
{
var rows = (
from a in dc.vPAQSummaries
select new Assessment()
{
PAQNumber = a.PAQNumber.Trim(),
CustomerID = (int)a.CustomerID,
Department = a.Department.Trim(),
CustomerName = a.CustomerName.Trim(),
DOTNumber = a.DOTNumber.Trim(),
OrgName = a.OrgName.Trim(),
DateEntered = a.DateEntered,
GroupNumber = a.GroupNumber.Trim(),
JobTitle = a.JobTitle.Trim(),
FileNames = a.FileNames.Trim(),
AnalystType = a.AnalystType.ToString(),
Incumbents = a.Incumbents,
});
// Filter by Customer ID
if (filter.CustomerID > 0)
{
rows = rows.Where(r => r.CustomerID == filter.CustomerID);
}
else
{
rows = rows.Where(r => r.CustomerID != null);
}
// Filter by DOT Number
if (!string.IsNullOrEmpty(filter.DOTNumberFrom))
{
if (string.IsNullOrEmpty(filter.DOTNumberTo))
{
rows = rows.Where(r => r.DOTNumber == filter.DOTNumberFrom);
}
else
{
rows = rows.Where(r => r.DOTNumber.CompareTo(filter.DOTNumberFrom) >= 0
&& r.DOTNumber.CompareTo(filter.DOTNumberTo) <= 0);
}
}
// Filter by OrgName
if (!string.IsNullOrEmpty(filter.OrgName))
{
rows = rows.Where(r => r.OrgName.StartsWith(filter.OrgName));
}
// Filter by Group
if (!string.IsNullOrEmpty(filter.GroupNumberFrom))
{
if (!string.IsNullOrEmpty(filter.GroupNumberTo))
{
rows = rows.Where(r => r.GroupNumber == filter.GroupNumberFrom);
}
else
{
rows = rows.Where(r => r.GroupNumber.CompareTo(filter.GroupNumberFrom) >= 0
&& r.GroupNumber.CompareTo(filter.GroupNumberTo) <= 0);
}
}
if (filter.Skip > 0)
{
rows = rows.Skip(filter.Skip);
}
if (filter.Take > 0)
{
rows = rows.Take(filter.Take);
}
else
{
rows = rows.Take(100);
}
return rows.Distinct();
}
}
}
The paging problem was caused by the Using statement. Changing this:
using (PAQcDataLayerDataContext dc = new PAQcDataLayerDataContext())
{
...
}
to this:
PAQcDataLayerDataContext dc = new PAQcDataLayerDataContext();
Made paging work. Now I have to figure out how sorting works.

LINQ refactoring help needed

How would you refactor this code, with respect to the LINQ? I'm new to LINQ and haven't quite have a good handle on more complex queries (nested, grouping).
Can all of these three statements and foreach loop been converted into one LINQ statement?
void AddSeries(Series series, int phraseId)
{
using (var db = Database.Instance)
{
foreach (var date in db.Ad.Select(ad => ad.DateTime.Date).Distinct())
{
var phraseCount = (from pc in db.PhraseCount
where pc.DateTime.Date == date &&
pc.PhraseId == phraseId
select pc.Count).SingleOrDefault();
var adCount = db.Ad.Where(ad => ad.DateTime.Date == date).Count();
series.Add(date, phraseCount / adCount);
}
}
}
Here's my first shot. Hard without having your model.
var q = from ad in db.Ad
group ad by ad.DateTime.Date into g
select new
{
AdCount = g.Count(),
Date = g.Key,
PhraseCount = (from pc in db.PhraseCount
where pc.DateTime.Date == g.Key
&& pc.PhraseId == phraseId
select pc).Count()
}

Resources