How to get record with max date with join? - c#

How can I do this in LINQ?
select MAX(d.DepartureDateRange),MAX(d.ReturnDateRange)
from Tour t join
TourCategory tc on t.ID = tc.TourID
join TourDates td on t.ID = td.TourID
join Dates d on d.ID = td.DatesID
where tc.CategoryID = 3 and t.ID = 12
Database diagram is here ->
For example joins is like this but i cannot get Max of DepartureDateRange & ReturnDateRange
var query2 = from t in db.Tour
join tc in db.TourCategory on t.ID equals tc.TourID
join td in db.TourDates on t.ID equals td.TourID
join d in db.Dates on td.DatesID equals d.ID
where tc.CategoryID == 3
select new IndexTour
{
ID = t.ID,
TourName = t.TourName,
//DepartureDateRange =
//ReturnDateRange =
Description = t.SmallDesc,
Price = t.Price,
CoverPhotoUrl = t.CoverPhotoUrl,
TourProgram = t.TourDesc
};
Thanks in advance.

Here it is (dates are grouped by Tour):
var query2 =
from t in db.Tour
join tc in db.TourCategory on t.ID equals tc.TourID
where tc.CategoryID == 3
// join dates aggregates grouped by tour id
join tdates in
from td in db.TourDates
join d in db.Dates on td.DatesID equals d.ID
group d by td.TourID into grp
select new
{
tourID = grp.Key,
departure = grp.Max(g => g.DepartureDateRange),
rtrn = grp.Max(g => g.ReturnDateRange)
}
on t.ID equals tdates.tourID
select new IndexTour
{
ID = t.ID,
TourName = t.TourName,
DepartureDateRange = tdates.departure,
ReturnDateRange = tdates.rtrn,
Description = t.SmallDesc,
Price = t.Price,
CoverPhotoUrl = t.CoverPhotoUrl,
TourProgram = t.TourDesc
};

I think this is what you want?
var dateRanges = tours
.Join(tourCategories,
t => t.Id,
tc => tc.TourId,
(t, tc) => (t, tc))
.Join(tourDates,
ttc => ttc.t.Id,
td => td.TourId,
(ttc, td) => (ttc, td))
.Join(dates,
ttctd => ttctd.td.DateId,
d => d.Id,
(ttctd, d) =>
new {
TourId = ttctd.ttc.t.Id,
CategoryId = ttctd.ttc.tc.CategoryId,
DepartureDateRange = d.DepartureDateRange,
ReturnDateRange = d.ReturnDateRange
});
var filtered = dateRanges
.Where(r => r.CategoryId == 3 && r.TourId == 12);
var maxDepartureDateRange = filtered.Max(d => d.DepartureDateRange);
var maxReturnDateRange = filtered.Max(d => d.ReturnDateRange);

Related

Why can't I select data from my LINQ sub query join?

I am trying to get data from 2 tables using a left join to a nested query. This allows me to get data from Item table but not the cart(nested query) table:
var q = from s in db.Items
join sub in (from c in db.Carts
where c.CartID == 1
group c by c.ItemID into g
select new
{
ItemID = g.Key,
Qty = g.Select(s => s.Qty)
}) on s.ItemID equals sub.ItemID into a
select new ItemViewModel
{
CategoryID = s.CategoryID,
Description = s.Description,
Price = s.Price,
**This being the issue------>>>>>>>** //Qty = a.Select(j => j.Qty),
ItemID = s.ItemID,
ItemName = s.ItemName
};
viewModel = q.ToList();
The query i am trying to acheive is:
select Items.*, Cart.Qty
from Items
left join (select ItemID, Qty from carts where CartID = 1 ) Cart
on Items.ItemID = Cart.ItemID
You can use GroupJoin with SelectMany for LEFT JOIN SQL Query and get the desired output.
var result = db.Items.GroupJoin(db.Carts.Where(x => x.CartID == 1), item => item.ItemID, cart => cart.ItemID,
(item, cart) => new { item, cart })
.SelectMany(x => x.cart.DefaultIfEmpty(), (it, ca) =>
{
return new ItemViewModel
{
ItemName = it.item.ItemName,
Price = it.item.Price,
ItemID = it.item.ItemID,
// ... .... ....
// Fill the required columns from it.Item property..
Qty = ca != null ? ca.Qty : 0
};
}).ToList();
EDIT: The LINQ version with SelectMany.
var result = from s in db.Items
join sub in (from c in db.Carts
where c.CartID == 1
select c)
on s.ItemID equals sub.ItemID into joined
from row in joined.DefaultIfEmpty()
select new ItemViewModel
{
CategoryID = s.CategoryID,
Description = s.Description,
Price = s.Price,
Qty = row != null ? row.Qty : 0,
ItemID = s.ItemID,
ItemName = s.ItemName
};
The C# Fiddle with sample data.
If I'm understanding correctly, and assuming that ItemViewModel.Qty property is just an int, the simplest form of the query you want is:
var q = from item in items
join cart in
(from cart in carts where cart.CartID == 1 select cart)
on item.ItemID equals cart.ItemID into itemCarts
select new ItemViewModel
{
ItemID = item.ItemID,
Qty = itemCarts.Sum(cart => cart.Qty)
};
If you want to only slightly modify/fix your query:
var q = from s in db.Items
join sub in (from c in db.Carts
where c.CartID == 1
group c by c.ItemID into g
select new
{
ItemID = g.Key,
Qty = g.Sum(s => s.Qty)
// or Qty = g.Select(s => s.Qty)
// and below: Qty = a.SelectMany(x => x.Qty).Sum()
})
on s.ItemID equals sub.ItemID into a
select new ItemViewModel
{
CategoryID = s.CategoryID,
Description = s.Description,
Price = s.Price,
Qty = a.Sum(x => x.Qty),
ItemID = s.ItemID,
ItemName = s.ItemName
};

Split a string value in list using linq

I have a list with a column value like "0000000385242160714132019116002239344.ACK" i need to take last 6 digits from this value like "239344" without extension(.ack) when binding to the list.
And i need to find the sum of Salary field also.
My query looks like below.
var result = from p in Context.A
join e in B on p.Id equals e.Id
join j in Context.C on e.CId equals j.CId
where (e.Date >= periodFrom && e.Date <= periodTo)
group new
{
e,
j
} by new
{
j.J_Id,
e.Date,
e.Es_Id,
e.FileName,
j.Name,
e.ACK_FileName,
p.EmpSalaryId,
p.Salary
} into g
orderby g.Key.CId, g.Key.Es_Id, g.Key.Date, g.Key.FileName
select new
{
CorporateId = g.Key.CId,
ProcessedDate = g.Key.Date,
EstID = g.Key.Es_Id,
FileName = g.Key.FileName,
Name = g.Key.Name,
ack = g.Key.ACK_FileName,
EmpSalaryId = g.Key.EmpSalaryId,
Salary=g.Key.Salary
};
var Abc=result.ToList();
var result = (from p in Context.A
join e in B on p.Id equals e.Id
join j in Context.C on e.CId equals j.CId
where (e.Date >= periodFrom && e.Date <= periodTo)
group new { e, j } by new
{
j.J_Id,
e.Date,
e.Es_Id,
e.FileName,
j.Name,
ACK_FileName = e.ACK_FileName.Substring(e.ACK_FileName.IndexOf(".ACK") - 7, 11),
p.EmpSalaryId,
p.Salary
} into g
orderby g.Key.CId, g.Key.Es_Id, g.Key.Date, g.Key.FileName
select new
{
CorporateId = g.Key.CId,
ProcessedDate = g.Key.Date,
EstID = g.Key.Es_Id,
FileName = g.Key.FileName,
Name = g.Key.Name,
ack = g.Key.ACK_FileName,
EmpSalaryId = g.Key.EmpSalaryId,
Salary = g.Sum(item => item.Salary)
}).ToList();

Grouping and Sum some field with Sub query in LINQ

I'm trying to convert my sql query to linq, i confused about sum and grouping,
this is my query
SELECT
produk.supplier,
SUM(transaksi.jumlah_transaksi),
SUM(transaksi.nominal_transaksi),
operasional.nominal
FROM
transaksi INNER JOIN produk ON transaksi.id_produk = produk.id_produk
LEFT JOIN
(SELECT
operasional.id_supplier,
SUM(nominal) AS nominal
FROM
operasional) operasional
ON operasional.id_supplier = produk.id_supplier
GROUP BY produk.supplier
output should be
like this
Progress
i am just trying with linq query like this without grouping
var result = from t in db.transaksi
join p in db.produk on t.id_produk equals p.id_produk
from op in
(
from o in db.operasional
select new
{
id_supplier = o.id_supplier,
nominal = o.nominal
}
).Where(o => o.id_supplier == p.id_supplier).DefaultIfEmpty()
select new
{
nama_supplier = p.supplier,
jumlah_transaksi = t.jumlah_transaksi,
nominal_transaksi = t.nominal_transaksi,
biaya_operasional = op.nominal
};
and result query from my linq still like this
SELECT
`p`.`supplier`,
`t`.`jumlah_transaksi`,
`t`.`nominal_transaksi`,
`t1`.`nominal`
FROM
`transaksi` `t`
INNER JOIN `produk` `p`
ON `t`.`id_produk` = `p`.`id_produk`
LEFT JOIN `operasional` `t1`
ON `t1`.`id_supplier` = `p`.`id_supplier`
Solved
and this is my full linq
var result = from t in db.transaksi
join p in db.produk on t.id_produk equals p.id_produk
from op in
(
from o in db.operasional
group o by o.id_supplier into g
select new
{
id_supplier = g.First().id_supplier,
nominal = g.Sum(o => o.nominal)
}
).Where(o => o.id_supplier == p.id_supplier).DefaultIfEmpty()
select new
{
nama_supplier = p.supplier,
jumlah_transaksi = t.jumlah_transaksi,
nominal_transaksi = t.nominal_transaksi,
biaya_operasional = op.nominal
};
var grouped = result
.GroupBy(x => x.nama_supplier)
.Select(x => new
{
nama_supplier = x.Key,
jumlah_transaksi = x.Sum(s => s.jumlah_transaksi),
nominal_transaksi = x.Sum(s => s.nominal_transaksi),
biaya_operasional = x.Select(s => s.biaya_operasional).First()
});
Try to use GroupBy (in following code result is your query from code above):
var grouped = result
.GroupBy(x => x.nama_supplier)
.Select(x => new {
nama_supplier = x.Key,
sum1 = x.Sum(s => s.jumlah_transaksi),
sum1 = x.Sum(s => s.nominal_transaksi),
nominal = x.Select(s => s.biaya_operasional).First()
})
Code is not checked so use it just as idea.

Not counting null values from a linq LEFT OUTER JOIN query

I have this sql query that does exactly what i want but i need it in linq. It returns a few AVC rows and counts how many PersonAVCPermission that has status 1 linked to it
SELECT a.Id, a.Name, a.Address, COUNT(p.AVCID) AS Count
FROM AVC AS a
LEFT OUTER JOIN
(
SELECT PersonAVCPermission.AVCId
FROM PersonAVCPermission
WHERE PersonAVCPermission.Status = 1
) AS p
ON a.Id = p.AVCId
GROUP BY a.Id, a.Name, a.Address
I have this query in linq and it does the same thing except when there are no PersonAVCPermission it still counts 1
var yellows = odc.PersonAVCPermissions.Where(o => o.Status == (int)AVCStatus.Yellow);
var q = from a in odc.AVCs
from p in yellows.Where(o => o.AVCId == a.Id).DefaultIfEmpty()
group a by new { a.Id, a.Name, a.Address } into agroup
select new AVCListItem
{
Id = agroup.Key.Id,
Name = agroup.Key.Name,
Address = agroup.Key.Address,
Count = agroup.Count(o => o.Id != null)
};
Im guessing that with DefaultIfEmpty() it places null rows in the list that then gets counted so i try to exclude them with (o => o.Id != null) but it still counts everything as at least one
If i dont use DefaultIfEmpty() it skips the rows with count 0 completely
How can i exclude them or am i doing it completely wrong?
How about using .Any() and a Let?
var yellows = odc.PersonAVCPermissions.Where(o => o.Status == (int)AVCStatus.Yellow);
var q = from a in odc.AVCs
let Y = (from p in yellows.Where(o => o.AVCId == a.Id) select p).Any()
where Y == true
group a by new { a.Id, a.Name, a.Address } into agroup
select new AVCListItem
{
Id = agroup.Key.Id,
Name = agroup.Key.Name,
Address = agroup.Key.Address,
Count = agroup.Count(o => o.Id != null)
};
You don't need the join, nor the grouping:
var q = from a in odc.AVCs
select new AVCListItem
{
Id = a.Id,
Name = a.Name,
Address = a.Address,
Count = yellows.Where(o => o.AVCId == a.Id).Count()
};

Unwind/Flatten Entity Framework result

Original SQL Query:
SELECT e.id, e.[type_id], e.name
FROM [user] u
JOIN user_group ug ON ug.[user_id] = u.id
JOIN usergroup grp on grp.id = ug.group_id
JOIN access_entity ae ON ae.group_id = grp.id
JOIN entity e on e.id = ae.entity_id
WHERE u.id = 184
GROUP BY e.id, e.[type_id], e.name
UNION
SELECT e.id, e.[type_id], e.name
FROM [user] u
JOIN user_group ug ON ug.[user_id] = u.id
JOIN usergroup grp on grp.id = ug.group_id
JOIN CRUD xs on xs.FK_Group_ID = grp.id
JOIN entity_type et on et.id = xs.FK_TypeID
JOIN entity e on e.[type_id] = et.id
WHERE u.id = 184
AND e.confidential = 0
AND xs.[Read] = 1
GROUP BY e.id, e.[type_id], e.name
Translated to Linq to Sql:
var A = M.users
.Join(M.user_groups, u => u.id, ug => ug.user_id, (u, ug) => new { u = u, ug = ug })
.Join(M.usergroups, x => x.ug.group_id, grp => grp.id, (x, grp) => new { u = x.u, ug = x.ug, grp = grp })
.Join(M.access_entities, x => x.grp.id, ae => ae.group_id, (x, ae) => new { u = x.u, ug = x.ug, grp = x.grp, ae = ae })
.Join(M.entities, x => x.ae.entity_id, e => e.id, (x, e) => new { u = x.u, ug = x.ug, grp = x.grp, ae = x.ae, e = e })
.Where(x => x.u.id == Global.CurrentUser.id);
var B = M.users
.Join(M.user_groups, u => u.id, ug => ug.user_id, (u, ug) => new { u = u, ug = ug })
.Join(M.usergroups, x => x.ug.group_id, grp => grp.id, (x, grp) => new { u = x.u, ug = x.ug, grp = grp })
.Join(M.CRUDs, x => x.grp.id, xs => xs.FK_Group_ID, (x, xs) => new { u = x.u, ug = x.ug, grp = x.grp, xs = xs })
.Join(M.entity_types, x => x.xs.FK_TypeID, et => et.id, (x, et) => new { u = x.u, ug = x.ug, grp = x.grp, xs = x.xs, et = et })
.Join(M.entities, x => x.et.id, e => e.type_id, (x, e) => new { u = x.u, ug = x.ug, grp = x.grp, xs = x.xs, e = e })
.Where(x => x.u.id == Global.CurrentUser.id && x.xs.Read && x.e.confidential == 0);
var RestrictedEntities = A.Select(x => x.e).Union(B.Select(x => x.e));
The problem is that the Entity Framework doesn't show tables like user_group, etc, since it's just a 1:* connection table.
In Entity Framework, I can basically do:
IQueryable<IEnumerable<IEnumerable<entity>>> Entities = this.ObjectContext.users.Select(u => u.usergroups.Select(ug => ug.access_entity.Select(ae => ae.entity)));
Is there a way to have that returned as just a
IQueryable<entity>
?
Is SelectMany what you are after?
I believe
this.ObjectContext.users.SelectMany(
u => u.usergroups.SelectMany(
ug => ug.access_entity.Select(ae => ae.entity)));
should have type IEnumerable<entity>.

Categories

Resources