Hide Join if string.IsNullOrEmpty using Linq - linq

I got this linq query which searches for selected values in my database using dropdowns.
Is there a way to hide the "join" in the linq query if the ddlCategory is null? I want this because the result of the search shows duplicated-rows because my documents can have many Categories.?? hope you understand what i mean.. Can anyone help??
var documents = from d in data.tblDocuments
join sc in data.tblSubCategories on d.DocId equals sc.DocId
orderby d.Docyear descending
where
(string.IsNullOrEmpty(person) || d.DocPerson.Equals(person)) &&
(string.IsNullOrEmpty(year) || d.Docyear.Equals(year)) &&
(string.IsNullOrEmpty(law) || d.DocLaw.Equals(law)) &&
(string.IsNullOrEmpty(court) || d.DocCourt.Equals(court)) &&
(string.IsNullOrEmpty(category) || sc.CategoryId.Equals(category)) &&
(string.IsNullOrEmpty(casenr) || d.DocNr.Equals(casenr))
select d;

Use lambda syntax:
var query = data.tblDocuments;
if (condition) // conditionally add join
query = query.Join(data.tblSubCategories.Where(sc => sc.CategoryId == category),
d => d.DocId, sc => sc.DocId, (d,sc) => d);
// continue to compose query
query = query.OrderByDescending(d => d.Docyear)
.Where(d => ...);
BTW you can compose filtering based on conditions:
if (!String.IsNullOrEmpty(person))
query = query.Where(d => d.DocPerson == person);

Related

Left joining a table's id with the maximum id from a subquery

I am using .NET core and trying to write a Linq query to list Cases. I have 3 tables that I am trying to join together:
Cases - Includes CaseID and CaseStatusID
CaseStatuses - Includes CaseStatusID (a Case has one of these)
CaseStatusHistory - Includes CaseStatusHistoryID, CaseID, CaseStatusID (a Case has many of these).
I can join Cases and CaseStatuses easily on CaseStatusID but am not sure how to join CaseStatusHistory on CaseStatusHistoryID = a subquery selecting the MAX(CaseStatusHistoryID) WHERE CaseID and CaseStatusID matches. I could even select the CaseStatusHitory later in my results but am not sure how.
This is what I need to convert
SELECT
c.CaseID,
csh.DateTimeAdded
FROM dbo.Cases c
JOIN dbo.CaseStatuses cs
ON c.CaseStatusID = cs.CaseStatusID
LEFT JOIN dbo.CaseStatusHistory csh
ON csh.CaseStatusHistoryID =
(
SELECT MAX(CaseStatusHistoryID)
FROM dbo.CaseStatusHistory
WHERE CaseID = c.CaseID
AND cs.CaseStatusID = c.CaseStatusID
)
This is what I have so far in Linq
IQueryable<CasesViewModel> objs =
from c in _db.Cases
from cs in _db.CaseStatuses.Where(cs => cs.CaseStatusId == c.CaseStatusId.Value).DefaultIfEmpty()
select new CasesViewModel
{
CaseID = c.CaseId,
CaseStatus = cs.CaseStatus
//StatusChangeDate = csh.DateTimeAdded
};
I need to add something like this
From csh In CaseStatusHistories
Where
(
From _csh In CaseStatusHistories
Where _csh.CaseID = c.CaseID AndAlso _csh.CaseStatusID = c.CaseStatusID
Select _csh.CaseStatusHistoryID
).Max = csh.CaseStatusHistoryID
Here is what I have so far but it does not return any result - just seems to time out.
IQueryable<CasesViewModel> objs =
from c in _db.Cases
from cs in _db.CaseStatuses.Where(cs => cs.CaseStatusId == c.CaseStatusId.Value).DefaultIfEmpty()
from rg in _db.RepairingGarages.Where(rg => rg.RepairingGarageId == c.RepairingGarageId.Value).DefaultIfEmpty()
from rgb in _db.Businesses.Where(rgb => rgb.BusinessId == rg.BusinessId.Value).DefaultIfEmpty()
from ec in _db.EngineeringCompanies.Where(ec => ec.EngineeringCompanyId == c.EngineeringCompanyId.Value).DefaultIfEmpty()
from ecb in _db.Businesses.Where(ecb => ecb.BusinessId == ec.BusinessId.Value).DefaultIfEmpty()
from csh in _db.CaseStatusHistory.Where(csh => csh.CaseStatusHistoryId ==
(
from _csh in _db.CaseStatusHistory
where _csh.CaseId == c.CaseId && _csh.CaseStatusId == c.CaseStatusId.Value
select _csh.CaseStatusHistoryId
).Max()).DefaultIfEmpty()
select new CasesViewModel
{
CaseID = c.CaseId,
RepairingGarage = rgb.BusinessName,
Engineer = ecb.BusinessName,
CaseStatus = cs.CaseStatus,
StatusChangeDate = csh.DateTimeAdded
};
I just need to get the StatusChangeDate which is the DateTimeAdded in the CaseStatusHistory table. Cases can be at the same status more than once, so I just need the DateTimeAdded with the highest CaseStatusHistoryID for a particular Case. Thank you very much for any help.
This appears to answer my question
IQueryable<CasesViewModel> objs =
from c in _db.Cases
from cs in _db.CaseStatuses.Where(cs => cs.CaseStatusId == c.CaseStatusId.Value).DefaultIfEmpty()
from rg in _db.RepairingGarages.Where(rg => rg.RepairingGarageId == c.RepairingGarageId.Value).DefaultIfEmpty()
from rgb in _db.Businesses.Where(rgb => rgb.BusinessId == rg.BusinessId.Value).DefaultIfEmpty()
from ec in _db.EngineeringCompanies.Where(ec => ec.EngineeringCompanyId == c.EngineeringCompanyId.Value).DefaultIfEmpty()
from ecb in _db.Businesses.Where(ecb => ecb.BusinessId == ec.BusinessId.Value).DefaultIfEmpty()
select new CasesViewModel
{
CaseID = c.CaseId,
RepairingGarage = rgb.BusinessName,
Engineer = ecb.BusinessName,
CaseStatus = cs.CaseStatus,
StatusChangeDate =
(
from _csh in _db.CaseStatusHistory
where _csh.CaseId == c.CaseId && _csh.CaseStatusId == cs.CaseStatusId
orderby _csh.CaseStatusHistoryId descending
select _csh.DateTimeAdded
).FirstOrDefault()
};
The only trouble with not joining is that I am not sure if I can sort by this date now. Any better ideas? Thank you.

LINQ Aggregate results with Many to Many Relationship

I am currently working with this schema
This is how my LINQ currently looks
var regionResults = (
from p in _context.Projects
from pr in p.Regions
where (data.RegionId == null || pr.RegionId == data.RegionId)
group p by pr.RegionId into g
join q in _context.Regions on g.Key equals _context.Regions.First().Id
select new Models.ViewModels.ProjectBreakdownViewModel.Regions
{
RegionName = q.Name,
TotalCount = g.Count(),
RejectedCount = g.Count(e => e.SubmissionStatusId == 2),
DeniedCount = g.Count(e => e.SubmissionStatusId == 3)
});
this is what it is currently producing, albeit incorrect
This is what I need it to be...
I know the problem is with this line, essentially
join q in _context.Regions on g.Key equals _context.Regions.First().Id
I don't know how to do this without the use of .First(), there doesn't seem to be a way to do it. I'm close I just don't know how to finish this.
If you have an collection of ProjectRegions in you Region entity, you can do this:
var result= context.Regions
.Where(r=> data.RegionId == null || r.Id == data.RegionId)
.Select(r=> new
{
RegionName = r.Name,
TotalCount = r.ProjectRegions.Count(),
RejectedCount = r.ProjectRegions.Count(e => e.Project.SubmissionStatusId == 2),
DeniedCount = r.ProjectRegions.Count(e => e.Project.SubmissionStatusId == 3)
});
ProjectRegion entity should have two nav properties, Project and Region, use them to navigate and create the corresponding conditions

Dynamic where condition in linq query expression

My Code :
IEnumerable<DataRow> whrRowEnum;
whrRowEnum = from r in dtInput.AsEnumerable()
where r.Field<string>("EMP_DEP") == "DEP1"
orderby EMP_DEP
select r;
The above code is working fine due to hard coded where condition, but In run-time I need to add multiple where condition in my linq query like r.Field("EMP_DEP") == "DEP1" && r.Field("EMP_ID") == "EMP1"
You can use lambda syntax to compose your query based on conditions:
IEnumerable<DataRow> query = dtInput.AsEnumerable();
if (condition1)
query = query.Where(r => r.Field<string>("EMP_DEP") == "DEP1");
if (condition2)
query = query.Where(r => r.Field<string>("EMP_ID") == "EMP1");
var whrRowEnum = query.OrderBy(r => r.Field<string>("EMP_DEP"));
Another option is adding conditions to query filter
whrRowEnum = from r in dtInput.AsEnumerable()
where (!condition1 || (r.Field<string>("EMP_DEP") == "DEP1")) &&
(!condition2 || (r.Field<string>("EMP_ID") == "EMP1"))
orderby EMP_DEP
select r;

Distinct keyword in linq query

my linq query returns duplicate records like below, how i have to use distinct keyword in this linq query.
var draft_recieved = from df in _DataContext.tblDrafts
from dfBody in _DataContext.DraftBodies
from sendUser in _DataContext.tblSends
where (df.DraftId == dfBody.DraftID) && (df.DraftId == sendUser.DraftId) &&
(sendUser.ToEmailId == (Guid)Membership.GetUser().ProviderUserKey)
select new
{
subject = dfBody.Subject,
draftid = df.DraftId
};
.Distinct() has to be applied as an extension method.
var draft_recieved = (from df in _DataContext.tblDrafts
from dfBody in _DataContext.DraftBodies
from sendUser in _DataContext.tblSends
where (df.DraftId == dfBody.DraftID) && (df.DraftId == sendUser.DraftId) &&
(sendUser.ToEmailId == (Guid)Membership.GetUser().ProviderUserKey)
select new
{
subject = dfBody.Subject,
draftid = df.DraftId
}).Distinct();

In Operator in Linq

I tried to use the suggestion provided here for using In operator in linq but, i am not able to convert my requirement into LINQ statement.
Below is the SQL query which i need to convert to Linq
select *
from navigator_user_field_property
where user_id = 'albert'
and field_id in (
select field_id
from navigator_entity_field_master
where entity_id = 1
and use_type = 0)
order by field_id
I want this to be converted to a Efficient Linq.
Most of the answers deal with the predetermined list of string array which is not working in my case.
Thanks
Looks like a join to me:
var query = from navigator in db.NavigatorUserFieldProperties
where navigator.UserId == "albert"
join field in db.NavigatorEntityFieldMasters
.Where(f => f.EntityId == 1 && f.UseType == 0)
on navigator.FieldId equals field.FieldId
select navigator;
Note that this will return the same value multiple times if there are multiple fields with the same ID - but I suspect that's not the case.
You could do a more literal translation like this:
var query = from navigator in db.NavigatorUserFieldProperties
where navigator.UserId == "albert" &&
db.NavigatorEntityFieldMasters
.Where(f => f.EntityId == 1 && f.UseType == 0)
.select(f => f.FieldId)
.Contains(navigator.FieldId)
select navigator;
... and that may end up translating to the same SQL... but I'd personally go with the join.
Here is an efficient and readable LINQ query:
var fields =
from field in db.navigator_entity_field_masters
where field.entity_id == 1 && field.user_type == 0
select field;
var properties =
from property in db.navigator_user_field_properties
where property.user_id == "albert"
where fields.Contains(property.field)
select property;
Look mama!! Without joins ;-)

Resources