how can this SQL be done in LINQ? - linq

i have this simple SQL query...
-- BestSeller
SELECT TOP(1) v.make, v.model, COUNT(v.make) AS NoSold
FROM Vehicles v
group by v.make, v.model
order by NoSold DESC
Im using entity framwork and want to do the same thing using linq. so far i have...
var tester = (from v in DB.VP_Historical_Vehicles
group v by v.make into g
orderby g.Count() descending
select new { make = g.Key, model = g, count = g.Count() }).Take(1);
foreach(var t in tester)
{
BestSeller.Make = t.make;
BestSeller.Model = t.make;
BestSeller.CountValue = t.count;
}
i keep getting timeouts, the database is large but the SQL runs very quick
any sugestions?
thanks
truegilly

Group by a compound key.
var t = (
from v in DB.VP_Historical_Vehicles
group v by new { v.make, v.model } into g
orderby g.Count() descending
select new { make = g.Key.make, model = g.Key.model, count = g.Count() }
)
.First();
BestSeller.Make = t.make;
BestSeller.Model = t.make;
BestSeller.CountValue = t.count;

Check what queries it performs when you run it with LINQ.
I suspect that you orderby g.Count() descending might be executing a COUNT query for each row and that would take a toll on performance to say the least.
When working with EF, always check what your LINQ statements produce in terms of queries. It is very easy to create queries that result in a n+1 scenario.

thanks to Scott Weinstein answer i was able to get it working
please comment if there is a more efficiant way of doing this...
VehicleStatsObject BestSeller = new VehicleStatsObject();
using (var DB = DataContext.Get_DataContext)
{
var t = (from v in DB.VP_Historical_Vehicles
group v by new { v.make, v.model } into g
orderby g.Count() ascending
select new { make = g.Key.make, model = g.Key.model, count = g.Count() }).OrderByDescending(x => x.count).First();
BestSeller.Make = t.make;
BestSeller.Model = t.model;
BestSeller.CountValue = t.count;
}
return BestSeller;

Related

Linq to SQL conversion...unable to add second COUNT

I'm trying to convert my SQL statement to a Linq statement and I'm not sure how to add the second COUNT to it. This is my SQL statement
SELECT l.Campus_Name, Labs = COUNT(*), LabsWithSubnets = COUNT(s.Lab_Space_Id)
FROM vw_Lab_Space l
LEFT JOIN vw_Subnet s on l.Lab_Space_Id = s.Lab_Space_Id
GROUP BY l.Campus_Name
ORDER BY 1
and this is my LINQ statement so far:
from l in Vw_Lab_Space
from s in Vw_Subnet
.Where(s => s.Lab_Space_Id == l.Lab_Space_Id)
.DefaultIfEmpty() // <=- triggers the LEFT JOIN
group l by new { l.Campus_Name } into g
orderby g.Key.Campus_Name
select new {
Campus_Name = g.Key.Campus_Name,
Labs = g.Count()
}
So I have everything but the LabsWithSubnets part in there. I'm just not sure how to add that in as I can't just do an s.Lab_Space_id.Count() in the select statement.
If you need table structure and sample data please see Need help creating an OUTER JOIN to count spaces.
Using your query as a basis, you need the groups to include s so you can count when non-null (I also removed the unnecessary anonymous object around the grouping key):
from l in Vw_Lab_Space
from s in Vw_Subnet
.Where(s => s.Lab_Space_Id == l.Lab_Space_Id)
.DefaultIfEmpty() // <=- triggers the LEFT JOIN
group new { l, s } by l.Campus_Name into g
orderby g.Key
select new {
Campus_Name = g.Key,
Labs = g.Count(),
LabsWithSubnets = g.Count(ls => ls.s != null)
}
However, rather than translate the SQL, I would probably take advantage of LINQ's group join to handle the query slightly differently:
var ans = from l in Vw_Lab_Space
join s in Vw_Subnet on l.Lab_Space_Id equals s.Lab_Space_Id into sj
group new { l, sj } by ls.Campus_Name into lsjg
select new {
Campus_Name = lsjg.Key,
NumLabs = lsjg.Count(),
LabsWithSubnets = lsjg.Sum(lsj => lsj.sj.Count())
};
PS Even in your query, I would use join...from...DefaultIfEmpty rather than from...from...where but depending on your database engine, may not matter.

LINQ Query To Return Duplicates Exclusively

I'm working on this LINQ query. I'd like the resulting list return a list of records that contain duplicates exclusively, based on the EMailAddress1 field and grouped by the EMailAddress1 field.
For instance:
emailaddress1#gmail.com
emailaddress1#gmail.com
emailaddress2#gmail.com
emailaddress2#gmail.com
emailaddress2#gmail.com
emailaddress3#gmail.com
emailaddress3#gmail.com
etc.
Any advice on this? Thanks.
var contacts = (from c in xrm.ContactSet
where c.StateCode != 1
orderby c.EMailAddress1, c.CreatedOn
descending select new {
c.FirstName,
c.LastName,
c.EMailAddress1,
c.ContactId,
c.CreatedOn }).ToList();
Based on your previous query:
var duplicatedEmails = (from c in contacts
group c by c.EMailAddress1 into g
where g.Count() > 1
select g.Key).ToList();
var duplicatedContacts = contacts.Where(c => duplicatedEmails.Contains(c.EMailAddress1));

How to find Distinct in more than one column in LINQ

I have a LINQ statement that returns many columns. I need to find distinct of unique combination of two columns. What is the best way to do this.
var productAttributeQuery =
from pa in ctx.exch_productattributeSet
join pp in ctx.exch_parentproductSet
on pa.exch_ParentProductId.Id equals pp.Id
join ep in ctx.exch_exchangeproductSet
on pp.exch_parentproductId equals ep.exch_ParentProductId.Id
where pa.exch_EffBeginDate <= effectiveDateForBeginCompare
&& pa.exch_EffEndDate >= effectiveDateForEndCompare
&& pa.statuscode == StusCodeEnum.Active
where pp.exch_EffBeginDate <= effectiveDateForBeginCompare
&& pp.exch_EffEndDate >= effectiveDateForEndCompare
&& pp.statuscode == StatusCodeEnum.Active
where ep.statuscode == StatusCodeEnum.Active
select new ProductAttributeDto
{
ParentProductId = pa.exch_ParentProductId.Id,
AttributeId = pa.exch_AttributeId.Id,
AttributeValue = pa.exch_Value,
AttributeRawValue = pa.exch_RawValue
};
return productAttributeQuery.ToList();
I want to get Distinct combination of ParentProductId and AttributeId from this list
You can group by anonymous type and select keys (they will be distinct)
var query = from p in productAttributeQuery
group p by new {
p.ParentProductId,
p.AttributeId
} into g
select g.Key;
You can use same approach with you original query if you want to get distinct pairs on server side.
Another approach - project results into pairs and get distinct from them:
var query = productAttributeQuery
.Select(p => new { p.ParentProductId, p.AttributeId })
.Distinct();

how use multiple join in linq?

var abc1 = from dlist in db.DebtorTransactions.ToList()
join war in db.Warranties on dlist.ProductID equals war.Id
join ag in db.Agents on war.fldAgentID equals ag.pkfAgentID
join sr in db.SalesReps on war.fldSrId equals sr.pkfSrID
where dlist.TransTypeID == 1
select new
{
dlist.Amount,
dlist.TransTypeID,
name = ag.Name,
ag.pkfAgentID,
sr.pkfSrID,
salesnam = sr.Name
} into objabc
group objabc by new
{
objabc.TransTypeID,
objabc.name,
objabc.salesnam,
objabc.Amount
};
var amt1 = abc1.Sum(x => x.Key.Amount);
var abc2 = from dlist in db.DebtorTransactions.ToList()
join cjt in db.CarJackaTrackas on dlist.ProductID equals cjt.pkfCjtID
join ag in db.Agents on cjt.AgentID equals ag.pkfAgentID
join sr in db.SalesReps on cjt.SalesRepId equals sr.pkfSrID
where dlist.TransTypeID == 0
select new
{
dlist.Amount,
dlist.TransTypeID,
name = ag.Name,
ag.pkfAgentID,
sr.pkfSrID,
enter code here` salesnam = sr.Name
} into objabc
group objabc by new
{
objabc.TransTypeID,
objabc.name,
objabc.salesnam,
objabc.Amount
};
var amt2 = abc1.Sum(x => x.Key.Amount);
//var result1=
return View();
i am new to linq, this query is working but i need to get the sum of Amount where dlist.TransTypeID == 0 and where dlist.TransTypeID == 1 by just single query. may anybody help me? thanks in advance
Here's a trimmed down example of how you can do it. You can add the joins if they are necessary, but I'm not clear on why you need some of the extra join values.
var transTypeAmountSums = (from dlist in db.DebtorTransactions
group dlist by dlist.TransTypeId into g
where g.Key == 0 || g.Key == 1
select new
{
TransTypeId = g.Key,
AmountSum = g.Sum(d => d.Amount)
}).ToDictionary(k => k.TransTypeId, v => v.AmountSum);
int transTypeZeroSum = transTypeAmountSums[0];
int transTypeOneSum = transTypeAmountSums[1];
A couple of things to note:
I removed ToList(). Unless you want to bring ALL DebtorTransactions into memory then run a Linq operation on those results, you'll want to leave that out and let SQL take care of the aggregation (it's much better at it than C#).
I grouped by dlist.TransTypeId only. You can still group by more fields if you need that, but it was unclear in the example why they were needed so I just made a simplified example.

Linq to Sql Query - better solution (optimizing)

The following code works, but it's not a nice code. (low performance)
I have a dictionary with value and key.
First i go trough every webcodes who exist. Then i load all participants in a list (where webcode equals the actual webcode in the foreach). After that i add the data (parameter of the webcode and a count of participants to the dictionary).
Guid compID = Guid.Parse(wID);
ChartModel webcodes = new ChartModel();
webcodes.Title = "Webcodes Statistics";
webcodes.Data = new Dictionary<string, int>();
var webcodesData = db.t_Webcode;
foreach (var w in webcodesData)
{
var wData = db.t_Participant.Where(t => t.FK_Competition == compID && t.Webcode == w.Webcode);
if (wData.Count() != 0)
webcodes.Data.Add(w.Parameter, wData.Count());
}
ViewBag.Webcodes = webcodes;
TIA
You need something along these lines:
webcodes.Data = (from w in db.t_Webcode
join p in db.t_Participant on w.Webcode equals p.Webcode
where p.FK_Competition == compID
group w by w.Parameter into g
select new { g.Key, Count = g.Count() }).ToDictionary();
I can't test it but that is the type of query you need.
This will assume that you have relationships defined in your database and that your LINQ to SQL datacontext are aware of them. If not, you will need to join manually on t_Participants from tWebcode.
This should execute in 1 single SQL query, instead of 1 query per row in tWebcode.
var webcodesAndNoOfParticipants =
from webcode in db.tWebcode
// Define number of participants for this webcode
let numberOfParticipants = webcode.t_Participants.Count(participant => participant.FK_Competition == compID)
where numberOfParticipants > 0
select new {
WebcodeParameter = webcode.Parameter,
NoOfParticipants = numberOfParticipants
};
webcodes.Data = webcodesAndNoOfParticipants.ToDictionary(x => x.WebcodeParameter, x => x.NoOfParticipants);

Resources