Because i need to do some filter condition feature ,I'm now want to translate a linq query to the lambda expression object.
linq code:
var query = from chlsynclog in oaPtDbContext.TableChlSyncLog
join mealchl in oaPtDbContext.TableMealChl on new { X1 = chlsynclog.Mealid, Y1 = chlsynclog.Chid } equals new { X1 = mealchl.Mealid, Y1 = mealchl.Chid }
into mealchlGroup
from mealchlGroupItem in mealchlGroup.DefaultIfEmpty()
join service in oaPtDbContext.TableService on mealchlGroupItem.Sid equals service.Sid
into serviceGroup
from serviceGroupItem in serviceGroup.DefaultIfEmpty()
join channel in oaPtDbContext.TableChannel on chlsynclog.Chid equals channel.Chid
into channelGroup
from channelGroupItem in channelGroup.DefaultIfEmpty()
join area in oaPtDbContext.TableArea on chlsynclog.Areaid equals area.Areaid
into areaGroup
from areaGroupItem in areaGroup.DefaultIfEmpty()
select new
{
chlsynclog.Id,
chlsynclog.Handset,
mealchlGroupItem.Mealname,
areaGroupItem.Proname,
areaGroupItem.Cityname,
chlsynclogType= GetChlsynclogType(chlsynclog.Type),
statusName=GetStatusName(chlsynclog.Statusid),
channelGroupItem.Chname,
syncTime=chlsynclog.Synctime.ToString("yyyy-MM-dd HH:mm:ss")
};
and I began to do this work,after i translated to the third
join
var testQuery =
oaPtDbContext.TableChlSyncLog
.GroupJoin(oaPtDbContext.TableMealChl,
(chlsynclog) => new
{
X1 = chlsynclog.Mealid,
X2 = chlsynclog.Chid
},
(mealchl) => new
{
X1 = mealchl.Mealid,
X2 = mealchl.Chid
},
(x, y) => new
{
X = x,
Y = y
})
.SelectMany(temp0 => temp0.Y.DefaultIfEmpty())
.GroupJoin(oaPtDbContext.TableService,
mealchl => mealchl.Sid,
service => service.Sid,
(x, y) => new { X = x, Y = y })
.SelectMany(temp0 => temp0.Y.DefaultIfEmpty())
.GroupJoin(oaPtDbContext.TableChannel,)
;
.GroupJoin(oaPtDbContext.TableChannel,)
The Second parameter just get the previous type's object TableService,
but i need the parameter should be the TableCholSynclog's Chid.
So here I have no idea to go on this work.
And I use the query.Expression.ToString() to see the expression:
<>h__TransparentIdentifier3.<>h__TransparentIdentifier2.<>h__TransparentIdentifier1.<>h__TransparentIdentifier0.chlsynclog.Chid
The sourcecode can do this but i can not !
So,How to write my lambda expression ????
Are you sure you want lambda?
var query = oaPtDbContext.TableChlSyncLog.GroupJoin(
oaPtDbContext.TableMealChl,
chlsynclog => new
{
X1 = chlsynclog.Mealid,
Y1 = chlsynclog.Chid
},
mealchl => new
{
X1 = mealchl.Mealid,
Y1 = mealchl.Chid
},
(chlsynclog, mealchlGroup) => new
{
chlsynclog,
mealchlGroup
})
.SelectMany(
#t => mealchlGroup.DefaultIfEmpty(),
(#t, mealchlGroupItem) => new
{
#t,
mealchlGroupItem
})
.GroupJoin(
oaPtDbContext.TableService,
#t => mealchlGroupItem.Sid,
service => service.Sid,
(#t, serviceGroup) => new
{
#t,
serviceGroup
})
.SelectMany(
#t => serviceGroup.DefaultIfEmpty(),
(#t, serviceGroupItem) => new
{
#t,
serviceGroupItem
})
.GroupJoin(
oaPtDbContext.TableChannel,
#t => chlsynclog.Chid,
channel => channel.Chid,
(#t, channelGroup) => new
{
#t,
channelGroup
})
.SelectMany(
#t => channelGroup.DefaultIfEmpty(),
(#t, channelGroupItem) => new
{
#t,
channelGroupItem
})
.GroupJoin(
oaPtDbContext.TableArea,
#t => chlsynclog.Areaid,
area => area.Areaid,
(#t, areaGroup) => new
{
#t,
areaGroup
})
.SelectMany(
#t => areaGroup.DefaultIfEmpty(),
(#t, areaGroupItem) => new
{
chlsynclog.Id,
chlsynclog.Handset,
mealchlGroupItem.Mealname,
areaGroupItem.Proname,
areaGroupItem.Cityname,
chlsynclogType = GetChlsynclogType(chlsynclog.Type),
statusName = GetStatusName(chlsynclog.Statusid),
channelGroupItem.Chname,
syncTime = chlsynclog.Synctime.ToString("yyyy-MM-dd HH:mm:ss")
});
Note : This was just Resharpers, Convert Linq to chain method feature. you can probably make this a loooot prettier.
Related
I need to create a LEFT OUTER JOIN in linq lambda syntax. The SQL I am trying to create a linq equivalent of is:
SELECT DISTINCT
p.PartNum AS PartNum, p.ShortChar01 AS SkuType,
vv.VendorID AS VendorCode,
p.PartDescription AS Description, p.Company AS Company
FROM
Part p WITH (NOLOCK)
INNER JOIN
PartPlant pp ON p.Company = pp.Company AND p.PartNum = pp.PartNum
LEFT OUTER JOIN
Vendor vv On pp.VendorNum = vv.VendorNum
WHERE
p.RefCategory = #refCategory
So as you can see its a fairly simple query joining a few tables. The issue is that it could happen that there is no vendor but we still want the rest of the information hence the left outer join.
My current attempt to recreate this is:
_uow.PartService
.Get()
.Where(p => p.RefCategory.Equals(level2))
.Join(_uow.PartPlantService.Get(),
p => new { p.PartNum, p.Company },
pp => new { pp.PartNum, pp.Company },
(p, pp) => new { Part = p, PartPlant = pp })
.GroupJoin(_uow.VendorService.Get(),
pprc => pprc.PartPlant.VendorNum,
v => v.VendorNum,
(pprc, v) => new { PPRC = pprc, V = v });
I am aware that the select isn't returning the same fields at the moment. I have ignored that for now as I am trying to ensure i am getting the correct values first.
The SQL query returns 41 records with 1 record having a null vendor. The linq query returns 40 records obviously not returning the one with the null vendor. I have tried using GroupJoin() and DefaultIfEmpty() but I cannot get it to work.
Any help would be greatly appreciated.
From the comment and links from user2321864, I managed to get it working as follows:
_uow.PartService.Get().Where(p => p.RefCategory.Equals(level2))
.Join(_uow.PartPlantService.Get(),
p => new { p.PartNum, p.Company },
pp => new { pp.PartNum, pp.Company },
(p, pp) => new { Part = p, PartPlant = pp })
.GroupJoin(_uow.VendorService.Get(),
pprc => pprc.PartPlant.VendorNum,
v => v.VendorNum,
(pprc, v) => new { PPRC = pprc, V = v })
.SelectMany(y => y.V.DefaultIfEmpty(),
(x, y) => new { PPRC = x.PPRC, Vendor = y })
.Select(r => new Level2Parts()
{
CompanyCode = r.PPRC.Part.Company,
Description = r.PPRC.Part.PartDescription,
PartNum = r.PPRC.Part.PartNum,
SkuType = r.PPRC.Part.ShortChar01,
VendorCode = r.Vendor.VendorID
})
.Distinct();
I am trying to convert this code:
var query2 = from b in db.MU_Reports
join downtime in db.Downtime_Reports on b.Shift equals downtime.Shift
where downtime.Downtime_Code.Equals("9185")
group downtime by new { b.Date, b.Shift, b.Machine_Number, b.MU } into g
select new
{
Date = g.Key.Date,
Shift = g.Key.Shift,
Machine = g.Key.Machine_Number,
MU = g.Key.MU,
No_Work_Hours = g.Sum(x => x.Total_DownTime)
};
To look something like this one:
var query = db.MU_Reports.Join(db.Downtime_Reports, b=> b.Shift, c=> c.Shift, (b , c) => new { b, thisshift = c })
.Where(n => n.thisshift.Down_TIme_Codes.Equals("9185"))
.GroupBy(d=> new { d.b.Date, d.b.Shift, d.b.Machine_Number, d.b.MU }, d => d.b)
.Select (g=> new
{
Date = g.Key.Date,
Shift = g.Key.Shift,
Machine = g.Key.Machine_Number,
MU = g.Key.MU,
No_Work_Hours = g.Sum(i => i.Total_DownTime)
}).ToList();
As you can see I am very close. My only issue is the last statement No_Work_Hours = g.Sum(i => i.Total_DownTime) It is trying to get the Total_DownTime from db.MU_Reports but it needs to come from db.Downtime_Reports. I am new to c# and am doing this to understand the program I created better.
Your second argument to GroupBy should be d => d.thisshift instead of d => d.b. That corresponds to the group downtime by, but by doing d => d.b it's like you're doing group b by
var query = db.MU_Reports
.Join(
db.Downtime_Reports,
b=> b.Shift,
c=> c.Shift,
(b , c) => new { b, thisshift = c })
.Where(n => n.thisshift.Down_TIme_Codes.Equals("9185"))
.GroupBy(
d=> new { d.b.Date, d.b.Shift, d.b.Machine_Number, d.b.MU },
d => d.thisshift)
.Select (g=> new
{
Date = g.Key.Date,
Shift = g.Key.Shift,
Machine = g.Key.Machine_Number,
MU = g.Key.MU,
No_Work_Hours = g.Sum(i => i.Total_DownTime)
})
.ToList();
This query below doesn't work because String.Join is not translatable.
PostgreSQL has the string_agg(expression, delimiter) feature though.
Is there anyway to use it from Linq?
var vwTourWithCategorieses = Context.Tours
.Join(Context.TourCategories, t => t.TourId, tc => tc.TourId,
(t, tc) => new { t.TourId, t.Name, tc.CategoryId})
.Join(Context.Categories, x => x.CategoryId, c => c.CategoryId,
(x, c) => new { x.TourId, TourName = x.Name, CategoryName = c.Name})
.GroupBy(x => new { x.TourId, x.TourName },
(key, c) => new VwTourWithCategories
{
TourId = key.TourId,
Name = key.TourName,
Categories = string.Join(",", c.Select(i => i.CategoryName))
})
.ToList();
Yes, unfortunately String.Join is not supported by EF, but I think you could project the result that you expect using Linq to objects after you materialize your query:
var query= Context.Tours
.Join(Context.TourCategories, t => t.TourId, tc => tc.TourId,
(t, tc) => new { t.TourId, t.Name, tc.CategoryId})
.Join(Context.Categories, x => x.CategoryId, c => c.CategoryId,
(x, c) => new { x.TourId, TourName = x.Name, CategoryName = c.Name})
.GroupBy(x => new { x.TourId, x.TourName }).ToList()
var result=query.Select( g=> new VwTourWithCategories
{
TourId = g.Key.TourId,
Name = g.Key.TourName,
Categories = string.Join(",", g.Select(i => i.CategoryName))
});
If you want to see all the CLR methods that are supported, you can check this link.
Update
Your query could be simpler if you use navigation properties. I think that is a many to many relationship, so you could do something like this:
var query= Context.Tours.Select(t=> new
{
t.TourId,
t.Name,
CategoryNames = t.TourCategories.Select(tc=>tc.Category.Name)
}
).ToList();
var result=query.Select( g=> new VwTourWithCategories
{
TourId = g.Key.TourId,
Name = g.Key.TourName,
Categories = string.Join(",", g.Select(i => i.CategoryName))
});
public IQueryable<DepartmentBreakdownReport> GetDepartmentBreakdownByReviewID(int ClientID, int? ReviewID) {
var x = (from d in camOnlineDb.Details
join h in camOnlineDb.Headers
on new { d.ClientID, d.ClaimID }
equals new { h.ClientID, h.ClaimID }
where h.ClientID == d.ClientID
join sd in camOnlineDb.SuppDepts
on new { a = d.ClientID, b = d.CategoryID ?? 0 }
equals new { a = sd.ClientID, b = sd.CategoryID }
join r in camOnlineDb.Reviews
on new { h.ClientID, h.ReviewID }
equals new { r.ClientID, r.ReviewID }
join rp in camOnlineDb.ReviewPeriods
on new { a = r.ClientID, b = r.ReviewPeriodID ?? 0 }
equals new { a = rp.ClientID, b = rp.ReviewPeriodID }
select new {
d.ClientID,
h.ReviewID,
sd.DepartmentID,
sd.DepartmentName,
d.Amount
});
x.GroupBy(r => new { r.DepartmentID, r.ReviewID, r.ClientID })
.Select(g => new {
ClientID = g.Key.ClientID,
ReviewID = g.Key.ReviewID,
Dept = g.Max(d => d.DepartmentName),
Amount = g.Sum(d => d.Amount)
})
.OrderBy(r => r.Dept)
.Where(r => r.ReviewID == 37);
//.Dump();
return x;
I know it has something to do with returning x. I tried returning is asQueryable but this didn't work. How do I get my statement to return x?
x is an IQueryable<T> where the T is the anonymous type with ClientID, ReviewID, DepartmentID, DepartmentName and Amount methods.
At some point you need to do a either a select new DepartmentBreakdownReport(…), as select new DepartmentBreakdownReport{…} a .Select(something => new DepartmentBreakdownReport(…)) or a .Select(something => new DepartmentBreakdownReport{…}). (Which are all the same thing really.
That will then give you an IQueryable<DepartmentBreakdownReport> because the type it has selected will be DepartmentBreakdownReport.
Note also that the code x.GroupBy(r => new { r.DepartmentID, r.ReviewID, r.ClientID }) and so on in your code effectively does nothing; it creates a new query, but then that new query is never used or even touched.
What I meant by my earlier comment(s) is that you want to create (and return) instances of DepartmentBreakdownReport, not an anonymous type.
return x.Where(r => r.ReviewID == 37)
.GroupBy(r => new { r.DepartmentID, r.ReviewID, r.ClientID })
.Select(g => new DepartmentBreakdownReport
{
ClientID = g.Key.ClientID,
ReviewID = g.Key.ReviewID,
Dept = g.Max(d => d.DepartmentName),
Amount = g.Sum(d => d.Amount)
})
.OrderBy(r => r.Dept);
I reordered the query a bit to my personal taste, but it should produce the same results.
Also, I don't know if you'll have to add an AsQueryable() on to the end of that or not...
for the following query can anyone please help me convert to lambda expression
SELECT p.partno,
sp.property,
count(s.serialNo) AS PropertyCount
FROM events e
JOIN Products p ON p.productguid = e.productguid
JOIN eventtypes et ON et.eventtypeguid = e.eventtypeguid
JOIN serialcontainerevent sce ON sce.EventGUID = e.EventGUID
JOIN serials s ON s.serialguid = sce.serialguid
JOIN statuses st ON st.statusguid = s.statusguid
LEFT OUTER JOIN serialproperties sp ON sp.serialguid = s.serialguid
WHERE p.partno = '21101'
AND st.code = 'NOTRECEIVED'
AND e.Field1Value = '21101'
AND e.Field2Value = '21101'
AND e.Field3Value = '21101'
AND e.Field4Value = '21101'
AND e.Field5Value = '21101'
AND sp.property = 'Delivery Date' --group by p.partno,s.serialno
GROUP BY p.partno,
sp.property
I think something as follows should get you started. Mind that you may need to optimize it depending on your actual data and relationships:
events
.Where(#event => #event.Field1Value == "21101" && #event.Field2Value == "21101" && #event.Field3Value == "21101" && #event.Field4Value == "21101" && #event.Field5Value == "21101")
.Join(products.Where(product => product.partno == "21101"), #event => #event.productguid, product => product.productguid, (#event, product) => new { #event, product })
.Join(eventtypes, y => y.#event.eventtypeguid, eventType => eventType.eventtypeguid, (y, eventType) => new { y, eventType })
.Join(serialcontainerevent, x => x.y.#event.EventGUID, serialContainerEvent => serialContainerEvent.EventGUID, (x, serialContainerEvent) => new { x, serialContainerEvent })
.Join(serials, w => w.serialContainerEvent.serialguid, serial => serial.serialguid, (w, serial) => new { w, serial })
.Join(statuses.Where(status => status.code == "NOTRECEIVED"), v => v.serial.statusguid, status => status.statusguid, (v, status) => new { v, status })
.GroupJoin(serialproperties.Where(serialProperty => serialProperty.property == "Delivery Date"), u => u.v.serial.serialguid, serialProperty => serialProperty.serialguid, (u, serialProperties) => new { u, serialProperties })
.SelectMany(t => t.serialProperties.Select(s => new { key = new { t.u.v.w.x.y.product.partno, s.property }, t }))
.GroupBy(r => r.key)
.Select(z => new { z.Key.partno, z.Key.property, PropertyCount = z.Where(q => q.t.u.v.serial.serialNo != null).Count() });