Linq to sql query: how to prevent duplication of code - c#

My problem
I'm very new to Linq and I have to difficulties using it. I have written functional queries but I was forced to duplicate some code in every single query. The first part for the queries is just there to give the structure of the database and remove corrupt data, so it always the same and it don't want to have several versions in my code.
What I tried
I made a function returning the portion of the query, but it won't compile and just gives an unexpected token error, so I'm lost.
My code
//always the same in each query : beginning
IQueryable<Lead> query = (from costumers in dc.T_costumers
join demands in dc.T_Demands on costumers.Costumer_FK equals typo.Typoe_PK
where
(dc.ISNUMERIC(costumers.Geoloc) == true) &&
costumers.longitudeClient != null
where (dc.ISNUMERIC(shop.id) == true)
//always the same in each query : end
where (temps.Date > new DateTime(2013, 4, 1).Date)
select new Lead
{
id = Convert.ToInt32(costumers.id),
});
Question
How do I wrote my queries so the common part is written only once in my code?

You can split query. First - select anonymous object with all linked entities:
var query =
from leads in dc.T_DM_FactDemandeWebLeads
join demands in dc.T_DM_DimDemandeWebs
on leads.DemandeWeb_FK equals demands.DemandeWeb_PK
join temps in dc.T_DM_Temps
on demands.DateDemande_FK equals temps.Temps_PK
join distributeurs in dc.T_DM_DimDistributeurs
on leads.Distributeur_FK equals distributeurs.Distributeur_PK
join geographies in dc.T_DM_DimGeographies
on distributeurs.DistributeurGeographie_FK equals geographies.Geographie_PK
join typologies in dc.T_DM_DimTypologies
on leads.Typologie_FK equals typologies.Typologie_PK
where (dc.ISNUMERIC(leads.GeolocDistanceRouteDistrib) == true) &&
leads.longitudeClient != null && typologies.CodeProcessus == "LEAD"
where (dc.ISNUMERIC(distributeurs.DistribIdPointDeVente) == true)
select new {
leads,
demands,
temps,
distributeurs,
geographies,
typologies
};
Second - write specific query:
var leads = from x in query
where (x.temps.Date > new DateTime(2013, 4, 1).Date)
where (x.temps.Date < new DateTime(2013, 5, 30).Date)
select new Lead {
id = Convert.ToInt32(x.leads.DemandeWeb_FK),
});

Related

Error: the specified linq expression contains references to queries that are associated with different context

I have this linq query that returns the revenue associated with every colorwaysid present within the given dates but it throws the SQLException:
the specified linq expression contains references to queries that are
associated with different context
using (var eshaktiDb = new eshaktiEntities())
{
using (var corpDb = new eshakti_corpEntities())
{
var queryResult =
from product in eshaktiDb.Products
join oivs in corpDb.OrderitemvalueSplits on product.ProductId equals oivs.Productid
join order in corpDb.Orders on oivs.Orderid equals order.OrderID
where product.ColorWaysId != null && order.CrDate >= fromDate && order.CrDate <= toDate
group oivs by product.ColorWaysId into g
select new ColorwayReportResponse
{
colorwayId = (int)g.Key,
revenue = (decimal)g.Sum(o => o.ActItemvalue + o.Custom)
};
return queryResult.ToList();
}
}
How to fix this ? Can somebody help me with the query that would fit in, also since the query involves two different databases, how can I get my desired result ?
I would separate this out into 2 separate queries starting with your corpDb:
var queryResult = (select * from corpDb.OrderitemvalueSplits join order in corpDb.Orders on oivs.Orderid equals order.OrderID).ToArray();
Then I would use perform the corresponding join afterwards in the other context.
var products = select * from product in eshaktiDb.Products join oivs in queryResult.OrderitemvalueSplits on product.ProductId equals oivs.Productid where product.ColorWaysId != null && order.CrDate >= fromDate && order.CrDate <= toDate
group oivs by product.ColorWaysId into g
select new ColorwayReportResponse
{
colorwayId = (int)g.Key,
revenue = (decimal)g.Sum(o => o.ActItemvalue + o.Custom)
};
There are other possible solutions to this issue here.
I'm not sure the above would work exactly in your code but generally you are not allowed to join within 2 separate contexts in Entity framework but you are allowed to pass arrays and other values between requests to accomplish the same task.

Is there a way to make this in linq?

I'm getting a sum of the checks that have been printed but haven't been cashed yet by checking 2 tabled in the database thru entitiyframework
I have tried multiple queries but I'm not too experienced in LINQ and I'm not getting the desired results, below is some of my implementations.
select sum(checks.Check_Amount) from dbo.ODC_Register checks
left join dbo.vw_BMO_Daily cashed
on checks.Check_Number = cashed.DCheckNo
where cashed.Id is null
and checks.Check_Date < '2019-9-3'
This is what i tried last
var missing = from checks in Context.ODC_Register
where(!Context.vw_BMO_Daily.Where(ma => Convert.ToInt32(ma.DCheckNo) == checks.Check_Number && checks.Check_Date <= ma.DatePosted).Any())
select new {checks.Check_Amount };
var missingSum = missing.Sum( x => x.Check_Amount);
All I need is to find a way to make this into a LINQ query
While a straight forward translation of your SQL is possible, perhaps using the GroupJoin would be a more LINQ friendly approach:
var ans = (from checks in Context.ODC_Register
where checks.Check_Date < new DateTime(2019, 9, 3)
join cashed in Context.vw_BMP_Daily on checks.Check_Number equals cashed.DCheckNo into cashedj
where !cashedj.Any()
select checks.Check_Amount).Sum();
PS Not sure why the range variable for ODC_Register is named checks since it is for one check at a time - I would call it check.
PPS In SQL and LINQ, a not exists test is usually preferable to using an empty left join:
var an2 = (from checks in Context.ODC_Register
where checks.Check_Date < new DateTime(2019, 9, 3)
where !Context.vw_BMP_Daily.Any(cashed => cashed.DCheckNo == checks.Check_Number)
select checks.Check_Amount).Sum();

Object reference not set to an instance of an object on querying from different lists [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 8 years ago.
I have the linq below. Since I am querying from 2 datacontexts, I've brokendown the tables into var list. But then, I have the error "Object reference not set to an instance of an object". This happens because edr is null.
var meetingsQuery = (from s in this.ModelContext.Meetings select s).ToList();
var deliverablesQuery = (from s in this.ModelContext.Deliverables select s).ToList();
var deliverableDatesQuery = (from s in this.ModelContext.DeliverableDates select s).ToList();
var refDateTypesQuery = (from s in this.ModelContext.RefDateTypes select s).ToList();
var refDeliverablesQuery = (from s in this.ModelContext.RefDeliverables select s).ToList();
var updatesQuery = (from s in this.ArenaUpdateBASEModelContext.Updates select s).ToList();
var updateQCsQuery = (from s in this.ArenaUpdateBASEModelContext.UpdateQCs select s).ToList();
var submissionUpdates = (from e in meetingsQuery
from edr in deliverablesQuery.Where(dr => dr.MeetingId == e.MeetingId && !dr.DeletedFlag).DefaultIfEmpty()
from ed in deliverableDatesQuery.Where(d => d.DeliverableId == edr.DeliverableId && !d.DeletedFlag && d.RefDateTypeId == 1).DefaultIfEmpty()
from ed2 in deliverableDatesQuery.Where(d2 => d2.DeliverableId == edr.DeliverableId && !d2.DeletedFlag && d2.RefDateTypeId == 2).DefaultIfEmpty()
join ret in refDateTypesQuery on ed.RefDateTypeId equals ret.RefDateTypeId
join rdt in refDeliverablesQuery on edr.RefDeliverableId equals rdt.RefDeliverableId
join upd in updatesQuery on edr.RefDsgnSubmissionTypeId equals upd.UpdateId
join uqc in updateQCsQuery on upd.UpdateId equals uqc.UpdateId
where
!e.DeletedFlag && !ret.DeletedFlag && !rdt.DeletedFlag && !upd.DeletedFlag && !uqc.DeletedFlag && e.ProjectId == arenaPiD// && rdt. .ObjectIdLink == "Update_UpdateId"
&& uqc.RefQCId == 6 // Distributed
&& uqc.RefQCStatusId == 2 // Complete
orderby e.ScheduledDT descending
select new
{
e.MeetingId,
e.ScheduledDT,
edr.DeliverableId,
edr.RefDeliverableId,
rdt.DeliverableAbbrv,
UpdateId = edr.RefDsgnSubmissionTypeId != null ? edr.RefDsgnSubmissionTypeId : 0,
RefRecommendationId = upd.RefRecommendationId != null ? upd.RefRecommendationId : 0,
uqc.RefQCId,
uqc.RefQCStatusId,
DeadlineDate = ed != null ? ed.DeliverableDateValue.ToString() : "",
ActualDate = ed2 != null ? ed2.DeliverableDateValue.ToString() : ""
}).ToList();
There's a big difference to how DefaultIfEmpty works for Linq To Objects vs Linq To SQL, which is tied into the difference between how nulls are handled between the two.
In SQL an empty record from a LEFT OUTER JOIN is populated with null values. Since your SQL never refer to the record itself this is not a problem. When you write edr.DeliverableId for an unmatched edr, the result is null.
Linq to SQL is different. When you try to reference any field or property of an unmatched edr the resultant error is exactly what you have seen. Every reference to edr after the DefaultIfEmpty call needs to be checked first to see if edr is valid.
Beyond the immediate error however...
You've mixed a couple of join forms - inner and outer - in that query, and the result is convoluted and unexpected. The problems you're taking on with DefaulIfEmpty for an outer join are negated with a subsequent inner join that depends on the outers. Which means that you are going through all the pain and suffering without any of the pay-off.
This block of joins:
join ret in refDateTypesQuery on ed.RefDateTypeId equals ret.RefDateTypeId
join rdt in refDeliverablesQuery on edr.RefDeliverableId equals rdt.RefDeliverableId
join upd in updatesQuery on edr.RefDsgnSubmissionTypeId equals upd.UpdateId
join uqc in updateQCsQuery on upd.UpdateId equals uqc.UpdateId
Every one of those depends ultimately on the outer join for edr, resulting in an output that - even if you put the time in to get the outer join side effects figured out - will negate the effects of DefaultIfEmpty.
You need to re-think your logic.
I suggest breaking this thing down into a series of intermediate queries. Build the query up one step at a time, joining the results in the final stage.
For instance, you have ed as an outer join which is then subjected to an inner join with rdt and further filtered by the properties of rdt in your where clause. Scrape all that out and put it in an intermediate, then join against it later. Do the same with edt: create an intermediate that join the parts. Flatten out the results for use in the final query.
Incidentally, you don't necessarily need to bring all of that data into memory. Even if your data is on different physical servers you can often still get Linq to SQL to talk to them. When you're targeting SQL Server for example you can specify a 3- or 4-part name for the Table attribute to access data in other databases on the same server or databases on linked servers. Might be useful.

How to Create the Left Join by using the group by data

I have three Table One is "Allowance " ,"Balance" and "TimeoffRequests" in these three table common columns are EmployeeId and TimeoffTypeId, Now i need to get the requested hours of one leave type by grouping thier timeoffTypeId and EmployeeId from the table "TimeoffRequests" , and got the "TimeOffHours". for the i wrote the code like
var query = (from tr in TimeOffRequests
where tr.EmployeeID == 9
group tr by new { tr.EmployeeID, tr.TimeOffTypeID } into res
select new
{
EmployeeID = res.Key.EmployeeID,
TimeOffTypeID = res.Key.TimeOffTypeID,
TotalHours = res.Sum(x => x.TimeOffHours)
}).AsEnumerable();
Now I need to join these results with the first table and have to get the all the employees, and timeoffTypes from the UserAllowance and corresponding TimeoffHours from the grouped table. for getting left joined query i wrote like below.
var requestResult = (from UA in UserAllowances
join UB in UserBalances on UA.EmployeeID equals UB.EmployeeID
where UA.TimeOffTypeID == UB.TimeOffTypeID && UA.EmployeeID == 9
&& UA.TimeOffType.IsDeductableType == true // LeftJoin
join rest in query on UA.EmployeeID equals rest.EmployeeID into penidngRequst
from penReq in penidngRequst.DefaultIfEmpty()
where penReq.TimeOffTypeID == UA.TimeOffTypeID
select new EmployeeTimeOffBalanceModel
{
TimeOffTypeID = UA.TimeOffTypeID != null ? UA.TimeOffTypeID : 0,
YearlyAllowanceHrs = (UA.YearlyAllowanceHrs != null) ? UA.YearlyAllowanceHrs : 0,
BalanceHours = UB.BalanceHrs != null ? UB.BalanceHrs : 0,
PendingHours = (decimal)((penReq != null) ? (penReq.TotalHours) : 0),
EmployeeID = UA != null ? UA.EmployeeID : 0,
}).ToList().Distinct();
It is giving only timeOFfType containing in grouped data,even though I wrote leftjoin for the query using the "into" and DefaultIfEmpty() keywords. the results becomes as like:
and by using the "linqPad" editor i found that it is applying the Cross or Outer Join instead of "left join" what will be the reason.
If I remove this line of code " where penReq.TimeOffTypeID
== UA.TimeOffTypeID" this showing all the timeoffTypes with cross join with repeatation like
How can I achieve left join with tables with Grouped data and showing null values if timeofftypes didn't having the any request?
You might want to move the where clause into the the on equals clause as shown below
join rest in query on new { UA.EmployeeID, UA.TimeOffTypeID } equals new { rest.EmployeeID, rest.TimeOffTypeID } into penidngRequst
from penReq in penidngRequst.DefaultIfEmpty()
You can change
where penReq.TimeOffTypeID == UA.TimeOffTypeID
to
where penReq == null || penReq.TimeOffTypeID == UA.TimeOffTypeID

C# LINQ: How to stack LINQ queries correctly

I have a form that allows the user to perform a myriad of searches. The table(s) that need to be joined differ depending on the search criteria entered. (My example below is very simplistic because both tables use the same sub-tables to join on, but the actual problem is not as simple.)
I've been using a technique I call LINQ stacking, like this:
IQueryable<LogENT> results = Context.AssignedLogsENT.Where(l => l.AgencyId);
if(txtFirstName.Text != null)
results = from r in results
join a in Context.LogAssignmentsENT on r.DisplayLogId equals a.LogId
join p in Context.PersonsENT on a.ObjectId equals p.DisplayPersonId
&& !a.Deleted &&
p.FirstName.StartsWith(Object.FirstName)
select r;
if(txtLastName.Text != null)
results = from r in results
join a in Context.LogAssignmentsENT on r.DisplayLogId equals a.LogId
join p in Context.PersonsENT on a.ObjectId equals p.DisplayPersonId
&& !a.Deleted &&
p.LastName.StartsWith(Object.LastName)
select r;
So you see if a certain text field is set, I add to the query as necessary. This actually works fine, except that when I use SQL Profiler to view the generated query, it is INNER JOINing the tables each time I add a new criterion.
i.e. the LogAssignments table is included 3, 4, 5 times. Is there a way I can prevent it from JOINing the same table more than once?
Or, is there a better way I can do this? I've looked at Predicate Builder however it doesn't seem to permit joining tables, which is a requirement in my case.
Thanks!
IQueryable<LogENT> results = Context.AssignedLogsENT.Where(l => l.AgencyId);
results = from r in results
join a in Context.LogAssignmentsENT on r.DisplayLogId equals a.LogId
join p in Context.PersonsENT on a.ObjectId equals p.DisplayPersonId
&& !a.Deleted
select r;
if(txtFirstName.Text != null)
results = from r in results
p.FirstName.StartsWith(Object.LastName)
select r;
if(txtLastName.Text != null)
results = from r in results
p.LastName.StartsWith(Object.LastName)
select r;
If you use just one query, you could modify it something like this:
results = from r in results
join a in Context.LogAssignmentsENT on r.DisplayLogId equals a.LogId
join p in Context.PersonsENT on a.ObjectId equals p.DisplayPersonId
&& !a.Deleted &&
(txtFirstName.Text != null || p.FirstName.StartsWith(Object.FirstName)) &&
(txtLastName.Text != null || p.LastName.StartsWith(Object.LastName))
select r;
You can build your base result and then dynamically add the where clauses.

Categories

Resources