I have an SQL expression
select S.SpecialtyName, COUNT(distinct SUC.SiteUserId) as Subscribers
from SiteUserContent SUC Inner join
Specialties S on SUC.SpecialtyId = S.SpecialtyId Inner join
SiteUser SU on SUC.SiteUserId = SU.SiteUserId
where SU.DeletedFlag = 0
group by S.SpecialtyName
Order by S.SpecialtyName
What will be the corresponding LINQ expression for the same?
from suc in context.SiteUserContent
join s in context.Specialties on suc.SpecialtyId equals s.SpecialtyId
join su in context.SiteUser on suc.SiteUserId equals su.SiteUserId
where su.DeletedFlag == 0
select new { suc.SiteUserId, s.SpecialityName } into x
group x by x.SpecialityName into g
orderby g.Key
select new {
SpecialityName = g.Key,
Subscribers = g.Select(i => i.SiteUserId).Distinct().Count()
}
Generated SQL will not be same, but I think result of query execution should be same.
var results = contex.SiteUserContent
.Join(context.Specialties, suc => suc.SpecialtyId, s => s.SpecialtyId, (suc, s) => new { suc, s })
.Join(context.SiteUser, i = i.suc.SiteUserId, su => su.SiteUserId, (i, su) => new { suc = i.suc, s = i.s, su = su })
.Where(i => i.su.DeletedFlag == 0)
.GroupBy(i => i.s.SpecialtyName)
.Select(g => new {
SpecialityName = g.Key,
Subscribers = g.Select(i => i.suc.SiteUserId)
.Distinct()
.Count()
})
.OrderBy(i => i.SpecialityName);
Related
This is my SQL query:
select
m.Name, s.Time, t.TheaterNumber
from
Movies m
join
MovieSeanceTheaters mst on mst.MovieId = m.MovieID
join
Theaters t on t.ID = mst.TheaterId
join
Seances s on mst.SeanceId = s.ID
This is my attempt at a Linq query:
var result = (from m in _context.Movies
join mst in _context.MovieSeanceTheaters on m.ID equals mst.MovieId
join t in _context.Theaters on mst.TheaterId equals t.ID
join s in _context.Seances on mst.TheaterId equals s.ID
select new { Film = m.Name, Salon = t.Name, Seans = s.Time }
).ToList();
I made this attempt, but I want to make with lambda for instance:
var result = movieManager.GetAll().Where(x => x.MovieSeanceTheaters)....
I couldn't do that.
If I understand you correctly, you want to rewrite your query from query syntax to method syntax?
Here we are!
var result = _context.Movies
.Join(_context.MovieSeanceTheaters,
m => m.MovieID,
mst => mst.MovieID,
(m, mst) => new
{
m = m,
mst = mst
})
.Join(_context.Theaters,
temp0 => temp0.mst.TheaterID,
t => t.ID,
(temp0, t) =>
new
{
temp0 = temp0,
t = t
})
.Join(_context.Seances,
temp1 => temp1.temp0.mst.TheaterID,
s => s.ID,
(temp1, s) =>
new
{
Film = temp1.temp0.m.Name,
Salon = temp1.t.TheaterNumber,
Seans = s.Time
});
Looks ugly, doesn't it?
Most often, the method syntax is more compact and convenient. But in this case, leave it as is.
I have an EF query that contains a number of aggregate sub queries (Count, Sum and Max). There are two problems.
I need the joins on the sub queries to be left joins so that records are returned even if there are no results in the aggregate sub queries. At present, records are only returned if all sub queries return records.
The resulting list of WholesaleCustomerAndAggregateOrders objects that are returned contain a Contact object that needs to also include Addresses and Counties. I added Include(c => c.Addresses.Select(a => a.Country)) to the query but the Contact objects don't contain any Address objects.
Any assistance with either issue would be appreciated. Full query below.
var month1Date = DateTime.Today.AddMonths(-1);
var month3Date = DateTime.Today.AddMonths(-3);
var month6Date = DateTime.Today.AddMonths(-6);
var month12Date = DateTime.Today.AddMonths(-12);
var db = GetNewContext();
var qry = from c in db.Contacts
.Include(c => c.Addresses.Select(a => a.Country))
join orderCount in
(
from o in db.WholesaleOrders
group o by o.ContactId into g
select new
{
ContactId = g.Key,
TotalOrders = g.Count()
}
) on c.Id equals orderCount.ContactId
join month1Value in
(
from o in db.WholesaleOrders
where o.OrderDate >= month1Date
group o by o.ContactId into g
select new
{
ContactId = g.Key,
TotalValue = g.Sum(r => r.LineItems.Sum(l => l.QuantityOrdered * l.Price))
}
) on c.Id equals month1Value.ContactId
join month3Value in
(
from o in db.WholesaleOrders
where o.OrderDate >= month3Date
group o by o.ContactId into g
select new
{
ContactId = g.Key,
TotalValue = g.Sum(r => r.LineItems.Sum(l => l.QuantityOrdered * l.Price))
}
) on c.Id equals month3Value.ContactId
join month6Value in
(
from o in db.WholesaleOrders
where o.OrderDate >= month6Date
group o by o.ContactId into g
select new
{
ContactId = g.Key,
TotalValue = g.Sum(r => r.LineItems.Sum(l => l.QuantityOrdered * l.Price))
}
) on c.Id equals month6Value.ContactId
join month12Value in
(
from o in db.WholesaleOrders
where o.OrderDate >= month12Date
group o by o.ContactId into g
select new
{
ContactId = g.Key,
TotalValue = g.Sum(r => r.LineItems.Sum(l => l.QuantityOrdered * l.Price))
}
) on c.Id equals month12Value.ContactId
join month12Quantity in
(
from o in db.WholesaleOrders
where o.OrderDate >= month12Date
group o by o.ContactId into g
select new
{
ContactId = g.Key,
OrderCount = g.Count()
}
) on c.Id equals month12Quantity.ContactId
join lastOrderDate in
(
from o in db.WholesaleOrders
group o by o.ContactId into g
select new
{
ContactId = g.Key,
LastOrderDate = g.Max(r => r.OrderDate)
}
) on c.Id equals lastOrderDate.ContactId
select new WholesaleCustomerAndAggregateOrders
{
Contact = c,
TotalOrders = orderCount.TotalOrders,
Month1Value = month1Value.TotalValue,
Month3Value = month3Value.TotalValue,
Month6Value = month6Value.TotalValue,
Month12Value = month12Value.TotalValue,
Month12OrderCount = month12Quantity.OrderCount,
LastOrderDate = lastOrderDate.LastOrderDate
};
return await qry.ToListAsync();
How about this:
db.WholesaleOrders
.GroupBy(o => o.ContactId)
.Select(a => new {
a.Key,
TotalOrders = a.Count(),
LastOrderDate = a.Max(r => r.OrderDate),
Month1Value = a.Where(b => b.OrderDate >= month1Date).Sum(r => r.LineItems.Sum(l => l.QuantityOrdered * l.Price),
Month3Value = a.Where(b => b.OrderDate >= month3Date).Sum(r => r.LineItems.Sum(l => l.QuantityOrdered * l.Price),
Month6Value = a.Where(b => b.OrderDate >= month6Date).Sum(r => r.LineItems.Sum(l => l.QuantityOrdered * l.Price),
Month12Value = a.Where(b => b.OrderDate >= month12Date).Sum(r => r.LineItems.Sum(l => l.QuantityOrdered * l.Price)
}).ToListAsync();
UPDATE: Add another property to projection:
Addresses = db.Addresses.Where(ad => ad.ContactId == a.Key);
where db is your context, and ad.ContactId is FK of the contact in Address table.
For this to work, multipleactiveresultsets property of the connection must be set to True.
How do I do this
Select top 10 Foo from MyTable
SELECT TOP (30) Item, Descripcion, SUM(Amount) AS Suma
FROM Venat
GROUP BY Item, Descripcion
ORDER BY Suma
in Linq to SQL?
with this only agrup by Item but not Description
var filtroprimeros30 = from nuevo in registrosVipDosAños
group nuevo by nuevo.Item into g
select new
{
Item = g.Key,
Suma = g.Sum(nuevo => nuevo.Amount)
};
Use anonymous type for grouping:
var filtroprimeros30 =
(from nuevo in registrosVipDosAños
group nuevo by new { nuevo.Item, nuevo.Description } into g // here
select new {
g.Key.Item,
g.Key.Description,
Suma = g.Sum(n => n.Amount)
})
.OrderBy(x => x.Suma)
.Take(30);
I'd actually go this way (because query syntax has nice syntax for grouping, but do not have ability to take N items):
var items = from n in registrosVipDosAños
group n by new { n.Item, n.Description } into g
select new {
g.Key.Item,
g.Key.Description,
Suma = g.Sum(x => x.Amount)
};
var topItems = items.OrderBy(x => x.Suma).Take(30);
Query still will be executed only once, but now it's more readable.
syntax alternative
var filtroprimeros30 = registrosVipDosAnos
.GroupBy(m => new {m.Item, m.Description})
.Select(g => new {
Item = g.Key.Item,
Description = g.Key.Description,
Suma = g.Sum(n => n.Amount)
})
.OrderBy(x => x.Suma)
.Take(30);
I have some SQL and am trying to make the equivalent in LINQ. This is the SQL:
SELECT Categories.CategoryDescription, Categories.CategoryType AS Type,
Categories.Category, COUNT(CategoryLinks.OrgID) AS CountOfOrgs
FROM CategoryLinks
INNER JOIN Categories ON Categories.CategoryID = CategoryLinks.CategoryID
GROUP BY Categories.Category, Categories.CategoryType, Categories.CategoryDescription
ORDER BY CategoryDescription ASC
Essentially, I want a list of everything from the Categories table and a count of the number of OrgId's in the CategoryLinks table that links to it.
Below is the query I am performing at the moment. There has to be a more efficient way to do this. Am I wrong?
var cnts = (from c in db.Categories
join cl in db.CategoryLinks on c.CategoryID equals cl.CategoryID
group new { c, cl } by new
{
c.CategoryID
} into g
select new
{
CategoryID = g.Key.CategoryID,
categoryCount = g.Count()
});
var results = (from c in db.Categories
join cn in cnts on c.CategoryID equals cn.CategoryID
select new
{
c.CategoryID,
c.CategoryDescription,
c.CategoryType,
Category = c.Category1,
cn.categoryCount
});
I think you want to use the GroupJoin method:
Categories.GroupJoin(
CategoryLinks,
x => x.CategoryID,
y => y.CategoryID,
(x,y) => new{
x.CategoryID,
x.CategoryDescription,
x.CategoryType,
Category = x.Category1,
CategoryCount = y.Count() })
In query syntax, this is written as join..into:
from c in db.Categories
join cl in db.CategoryLinks on c.CategoryID equals cl.CategoryID into catGroup
select new
{
c.CategoryID,
c.CategoryDescription,
c.CategoryType,
Category = c.Category1,
CategoryCount = catGroup.Count()
}
Try this:
var bbb = categories.Join(categoryLinks, c => c.CategoryID, cl => cl.CategoryId, (c, cl) => new {c, cl})
.GroupBy(g => g.c)
.Select(g => new {count = g.Count(), Category = g.Key});
It returns count and all data that is in Category. We group by all columns in category and place result in new anonymous type variable that contains 2 properties: Count, that contains count and Category that is of type Category and contains all data that is in category row.
If you want, you can rewrite it as:
var bbb = categories.Join(categoryLinks, c => c.CategoryID, cl => cl.CategoryId, (c, cl) => new {c, cl})
.GroupBy(g => g.c)
.Select(g => new
{
CategoryID = g.Key.CategoryId,
CategoryDescription = g.Key.CategoryDescription,
CategoryType = g.Key.CategoryType,
Category = g.Key.Category1,
categoryCount = g.Count()
});
I am trying to write equivalent linq code for following query.
SELECT A.*
FROM
(
SELECT * FROM TableA
WHERE id = 100
) a
JOIN
(
SELECT Name, MAX(AnotherId) AnotherId
FROM TableA
WHERE id = 100
GROUP BY Name
) b
on a.Name = b.Name and a.AnotherId = b.AnotherId
This is the linq
var Collection = from R in DbContext.TableA
join G in (DbContext.TableA.Where(r => r.Id == 100).GroupBy(r => new { r.Name, r.AnotherId } ).Select(g => new { Name = g.Name , AnotherId = g.Max(o => o.AnotherId) }))
on new { R.Name, R.AnotherId } equals new { G.Name, G.AnotherId }
where R.Id == 100
select R;
But I am getting following compilation error that I don’t know how to fix. Any thoughts
The type of one of the expressions in the join clause is incorrect. Type inference failed in the call to 'Join'.
Error 7 'System.Linq.IGrouping' does not contain a definition for 'Name' and no extension method 'Name' accepting a first argument of type 'System.Linq.IGrouping' could be found (are you missing a using directive or an assembly reference?)
You group by r.Name, r.AnotherId, when you just want to group by r.Name.
var Collection = from R in DbContext.TableA
join G in (DbContext.TableA
.Where(r => r.Id == 100)
.GroupBy(r => r.Name)
.Select(g => new { Name = g.Key , AnotherId = g.Max(o => o.AnotherId) }))
on new { R.Name, R.AnotherId } equals new { G.Name, G.AnotherId }
where R.Id == 100
select R;
And to have all in Fluent Syntax
var collection = DbContext.TableA
.Where(t1 => t1.Id == 100)
.Join(DbContext.TableA
.Where(t2 => t2.Id == 100)
.GroupBy(t2 => t2.Name)
.Select(group => new{Name = group.Key,
AnotherId = group.Max(e => e.AnotherId)})
),
t1 => new{t1.Name, t1.AnotherId} ,
t2 => new{t2.Name, t2.AnotherId},
(t1, t2) => t1);
llHi you need the following syntax, notice the addition of 'Key'
var Collection = from R in DbContext.TableA
join G in (DbContext.TableA.Where(r => r.Id == 100)
.GroupBy(r => new { r.Name, r.AnotherId } )
.Select(g => new { Name = g.Key.Name , AnotherId = g.Max(o => o.AnotherId) }))
on new { R.Name, R.AnotherId } equals new { G.Name, G.AnotherId }
where R.Id == 100
select R;
I would recommend using the query syntax for all parts of your query. By doing it this way, your linq query will have a more similar structure to your original sql query. It would look like this:
var query =
from a in
(from x in DbContext.TableA
where x.ID == 100
select x)
join b in
(from x in DbContext.TableA
where x.ID == 100
group x by x.Name into x
select new
{
Name = x.Key,
AnotherId = x.Max(o => o.AnotherId),
})
on new { a.Name, a.AnotherId } equals new { b.Name, b.AnotherId }
select a;
saj and Raphael both have found good points:
.GroupBy(r => new { r.Name, r.AnotherId } )
.Select(g => new { Name = g.Name , AnotherId = g.Max(o => o.AnotherId) }))
Groups don't have a Name. Each group has a Key (and the Key has a Name and AnotherId).
Since you want the Max(AnotherId), you don't want to include AnotherId in your grouping Key (same as it is not present in the GroupBy clause of the original query).
.GroupBy(r => r.Name) //the Name is the Key
.Select(g => new { Name = g.Key, AnotherId = g.Max(o => o.AnotherId) }))