I have the following entity:
#Entity
#Table(name = "follow_ups")
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
#Access(AccessType.FIELD)
public class FollowUp extends EntityObject {
private static final long serialVersionUID = -1343114665843716990L;
#ManyToOne(optional = false)
#JoinColumn(name = "contact_id")
private Contact contact;
#ManyToOne(optional = true)
#JoinColumn(name = "dossier_id")
private Dossier dossier;
#ManyToOne(optional = true)
#JoinColumn(name = "website_item_id")
private WebsiteItem websiteItem;
#ManyToOne(optional = true, fetch = FetchType.LAZY)
#JoinColumn(name = "invoice_id")
private Invoice invoice;
#Column(name = "message_date")
#OrderBy("message_date DESC")
private Date messageDate;
#Column(name = "message")
private String message;
#ManyToOne
#JoinColumn(name = "creator")
private BackendUser creator;
public Contact getContact() {
return contact;
}
public void setContact(Contact contact) {
this.contact = contact;
}
public Dossier getDossier() {
return dossier;
}
public void setDossier(Dossier dossier) {
this.dossier = dossier;
}
public WebsiteItem getWebsiteItem() {
return websiteItem;
}
public void setWebsiteItem(WebsiteItem websiteItem) {
this.websiteItem = websiteItem;
}
public Invoice getInvoice() {
return invoice;
}
public void setInvoice(Invoice invoice) {
this.invoice = invoice;
}
public BackendUser getCreator() {
return creator;
}
public void setCreator(BackendUser creator) {
this.creator = creator;
}
public Date getMessageDate() {
return messageDate;
}
public void setMessageDate(Date messageDate) {
this.messageDate = messageDate;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
When using a criteria that checks anything on the invoice, invoice.id for instance, or when the invoice is fetched eagerly, the following sql is created (this is only one of many queries that it executes):
SELECT vatdetails0_.invoice_id AS invoice_5_40_1_,
vatdetails0_.id AS id1_39_1_,
vatdetails0_.id AS id1_39_0_,
vatdetails0_.invoice_id AS invoice_5_39_0_,
vatdetails0_.invoice_vat_type AS invoice_2_39_0_,
vatdetails0_.vat AS vat3_39_0_,
vatdetails0_.vat_amount AS vat_amou4_39_0_
FROM invoice_vat_details vatdetails0_
WHERE vatdetails0_.invoice_id IN
(SELECT invoice11_.id
FROM website_lots l
WHERE l.website_item_id = websiteite14_.id
) = 0 THEN websiteite14_.end_date ELSE
(SELECT MAX(l.enddate)
FROM website_lots l
WHERE l.website_item_id = websiteite14_.id
)
END THEN
CASE
WHEN (SELECT COUNT(*)
FROM website_lots wl
INNER JOIN website_lots_auction wla
ON wl.id = wla.id
WHERE wla.status = 'AVAILABLE'
AND wl.website_item_id = websiteite14_.id) =
(SELECT COUNT(*)
FROM website_lots wl
INNER JOIN website_lots_auction wla
ON wl.id = wla.id
WHERE wl.website_item_id = websiteite14_.id
)
THEN 5
WHEN (SELECT COUNT(*)
FROM website_lots wl
INNER JOIN website_lots_auction wla
ON wl.id = wla.id
WHERE wla.status = 'AVAILABLE'
AND wl.website_item_id = websiteite14_.id) = 0
THEN 7
ELSE 6
END WHEN now() < websiteite14_.start_date THEN 2 WHEN now() >= websiteite14_.start_date THEN 1 ELSE -1
END WHEN websiteite14_.type = 'RENT' THEN 1 ELSE
CASE
WHEN (SELECT COUNT(*)
FROM website_lots
INNER JOIN lots
ON lots.id = website_lots.lot_id
WHERE website_lots.website_item_id = websiteite14_.id) =
(SELECT COUNT(*)
FROM website_lots
INNER JOIN lots
ON lots.id = website_lots.lot_id
WHERE lots.status = 'SOLD'
AND website_lots.website_item_id = websiteite14_.id
)
THEN 3
ELSE 1
END
END AS formula10_12_,
CASE
WHEN (SELECT COUNT(*)
FROM website_lots wl
LEFT JOIN website_lots_sale wls
ON wl.id=wls.id
LEFT JOIN website_lots_auction wla
ON wl.id =wla.id
WHERE wl.website_item_id = websiteite14_.id
AND (wls.status <> 'AVAILABLE'
OR wla.status <> 'AVAILABLE')) = 0
THEN 'ALL'
WHEN (SELECT COUNT(*)
FROM website_lots wl
LEFT JOIN website_lots_sale wls
ON wl.id=wls.id
LEFT JOIN website_lots_auction wla
ON wl.id =wla.id
WHERE wl.website_item_id = websiteite14_.id
AND (wls.status = 'AVAILABLE'
OR wla.status = 'AVAILABLE')) = 0
THEN 'NONE'
ELSE 'PART'
END AS formula11_12_,
CASE
WHEN (SELECT COUNT(*)
FROM website_lots l
WHERE l.website_item_id = websiteite14_.id) = 0
THEN websiteite14_.end_date
ELSE
(SELECT MAX(l.enddate)
FROM website_lots l
WHERE l.website_item_id = websiteite14_.id
)
END AS formula12_12_,
CASE
WHEN (SELECT COUNT(*)
FROM website_lots l
WHERE l.website_item_id = websiteite14_.id) = 0
THEN NULL
ELSE
(SELECT MAX(l.soldDate)
FROM website_lots l
WHERE l.website_item_id = websiteite14_.id
)
END AS formula18_12_,
websiteite14_.type AS type1_80_12_
FROM follow_ups this_
INNER JOIN contacts contact2_
ON this_.contact_id=contact2_.id
LEFT OUTER JOIN frontend_users frontendus3_
ON contact2_.id=frontendus3_.contact_id
LEFT OUTER JOIN backend_users backenduse4_
ON this_.creator=backenduse4_.id
LEFT OUTER JOIN dossiers dossier5_
ON this_.dossier_id=dossier5_.id
LEFT OUTER JOIN backend_users backenduse6_
ON dossier5_.applier_backend_user_id=backenduse6_.id
LEFT OUTER JOIN backend_users backenduse7_
ON dossier5_.owner_backend_user_id=backenduse7_.id
LEFT OUTER JOIN commissions commission8_
ON dossier5_.id=commission8_.dossier_id
LEFT OUTER JOIN commission_brackets commission9_
ON commission8_.id=commission9_.commission_id
LEFT OUTER JOIN contacts contact10_
ON commission8_.contact_id=contact10_.id
LEFT OUTER JOIN invoices invoice11_
ON this_.invoice_id=invoice11_.id
LEFT OUTER JOIN invoiceContacts invoicecon12_
ON invoice11_.id=invoicecon12_.invoice_id
LEFT OUTER JOIN contacts contact13_
ON invoicecon12_.contact_id=contact13_.id
LEFT OUTER JOIN website_items websiteite14_
ON this_.website_item_id=websiteite14_.id )
This query is incorrect, generated error is about the first THEN keyword which can not be used at that position, and I have never had hibernate do this before. On the internet is not that much information to find about hibernate generating a faulty query.
Criteria used is the simplest case:
session.createCriteria(getEntityClass())
What can be wrong and should I check out?
How can I dive into hibernate to see what the problem is?
Maybe it should be logged as a hibernate bug?
Used hibernate version is: 4.3.10.Final
Dialect used: POSTGRESQL.
Related
I have this SQL which I am trying to convert to LINQ , how can this be converted?
Is there an equivalent of Lag at all?
I see there is a case statement not sure how to use it
SELECT
ah.AuthHist_ID,
ah.F_ID,
CASE WHEN ah.AuthPIFlg = 1 OR ah.AuthPINVFlg = 1 THEN 'True' ELSE 'False' end AS chkReqPI,
lag(CASE WHEN ah.AuthPIFlg = 1 OR ah.AuthPINVFlg = 1 THEN 'True' ELSE 'False' end, 1, null) OVER (ORDER BY ah.f_id, ah.AuthHist_ID) AS prevChkReqPI,
ah.Cr8Dt,
lag(ah.Cr8Dt, 1, null) OVER (ORDER BY ah.f_id, ah.AuthHist_ID) AS prevCr8Dt,
cu.UserName AS Cr8UserName,
lag(cu.UserName, 1, null) OVER (ORDER BY ah.f_id, ah.AuthHist_ID) AS prevCr8UserName,
fh.UpdtDt,
FROM AuthHist Ah
LEFT JOIN User cu
ON Ah.Cr8User_ID = cu.User_ID
WHERE Ah.F_ID = #fid
return (from a in DbContext.AuthHist
join c DbContext.User on a.UpdtUserId equals c.UserId
where a.FId == fId
select new AuthHistEntity()
{
FId = a.FId,
checkReqPI = a.AuthPIflg = 1 || a.AuthPINVflg = 1 :
});
I have this SQL which I am trying to convert to LINQ , how can this be
converted?
You can use linq to do this, but it will be a bit more complicated.
For the case when in linq, you can directly use the ternary operator(?:) instead.
As for the Lag() function, we need to replace this function with another sql writing as follow:
(This is just to facilitate the understanding of the linq statement below, you do not need to change your sql statement)
select kh.AuthHist_ID,kh.F_ID,
CASE WHEN kh.AuthPIFlg = 1 OR kh.AuthPINVFlg = 1 THEN 'True' ELSE 'False' end AS chkReqPI,
CASE WHEN (ch.AuthPIFlg is null or ch.AuthPINVFlg is null) then Null when (ch.AuthPIFlg = 1 OR ch.AuthPINVFlg = 1) THEN 'True' ELSE 'False' end AS prevChkReqPI ,
kh.Cr8Dt,
ch.Cr8Dt AS prevCr8Dt ,
kh.UserName AS Cr8UserName,
cu.UserName AS prevCr8UserName
from
( select -1+row_number() over (order by ah.f_id,ah.AuthHist_ID) as row1, * from
(select * from AuthHist a left join User u on a.Cr8User_ID = u.User_ID) Ah) kh
left join (select * from AuthHist a left join User u on a.Cr8User_ID = u.User_ID) cu ON kh.row1 = cu.AuthHist_ID
left join AuthHist ch on kh.row1 = ch.AuthHist_ID where kh.F_ID =#fid
Because the types of some fields are uncertain, I have create the AuthHistEntity class as follow, you can modify some details according to your needs.
public class AuthHistEntity
{
public int AuthHist_ID { get; set; }
public int F_ID { get; set; }
public string chkReqPI { get; set; }
public string prevChkReqPI { get; set; }
public string Cr8Dt { get; set; }
public string prevCr8Dt { get; set; }
public string Cr8UserName { get; set; }
public string prevCr8UserName { get; set; }
}
Here is the linq writing, you can try it:
var newUser = (from a in DbContext.AuthHist
join u in DbContext.User on a.Cr8User_ID equals u.User_ID
select new { a, u }).ToList();
var newAuthList = (from t in newUser
select new
{
row_1 = t.a.AuthHist_ID - 1,
data = t
}).ToList();
int fid = 1;
var result = (from dt in
(from ch in newAuthList
join ah in DbContext.AuthHist on ch.row_1 equals ah.AuthHist_ID
into ot from otnew in ot.DefaultIfEmpty()
select new { T1 = ch, T2 = otnew == null ? new AuthHist() : otnew
}).ToList()
join nu in newUser on dt.T1.row_1 equals nu.a.AuthHist_ID
into yG from otnew in yG.DefaultIfEmpty()
where dt.T1.data.a.F_ID == fid
select new AuthHistEntity()
{
AuthHist_ID = dt.T1.data.a.AuthHist_ID,
F_ID = dt.T1.data.a.F_ID,
chkReqPI = (dt.T1.data.a.AuthPIFlg == 1 || dt.T1.data.a.AuthPINVFlg == 1) ? "True" : "False",
prevChkReqPI = (dt.T2.AuthPIFlg == null || dt.T2.AuthPINVFlg == null) ? null : ((dt.T2.AuthPIFlg == 1 || dt.T2.AuthPINVFlg == 1) ? "True" : "Flase"),
Cr8Dt = dt.T1.data.a.Cr8Dt,
prevCr8Dt = dt.T2.Cr8Dt == null ? null : dt.T2.Cr8Dt,
Cr8UserName = dt.T1.data.u.UserName,
prevCr8UserName = otnew == null ? null : otnew.u.UserName
}).ToList();
I'm trying to translate SQL native query usage in #Query("...", native=true) Spring Data Jpa annotation, to JPQL query usage within the same annotation.
SQL Query:
select d.id as doctorId, d.firstName as doctorFirstName, d.lastName as doctorLastName, d.title as doctorTitle,
d.email as doctorEmail, v.id as id, v.dateFrom as dateFrom, v.dateTo as dateTo, v.status as status,
md.id as medicalServicesId, md.service as medicalServicesService, md.price as medicalServicesPrice
from Visit v
left outer join Doctor d on v.doctor_id=d.id
left outer join visit_medical_services vms on v.id=vms.medical_services_id
left outer join MedicalService md on vms.visit_id=md.id
where d.id= :doctorId and v.status= :status and v.dateFrom>= :dateFrom and v.dateTo<= :dateTo
I'm using Spring Projected Interface, that's why columns aliases are named liked this.
Now i want to get exactly the same result with JPQL - list of items. What i did tried it's this:
#Query("select d.id as doctorId, d.firstName as doctorFirstName, d.lastName as doctorLastName, d.title as doctorTitle, d.email as doctorEmail, " +
"v.id as id, v.dateFrom as dateFrom, v.dateTo as dateTo, v.status as status, md.id as medicalServicesId, md.service as medicalServicesService, md.price as medicalServicesPrice \n" +
"from Visit v \n" +
"left outer join Doctor d on v.doctor.id=d.id \n" +
"left outer join v.medicalServices vms on vms.id=v.id \n" +
"left outer join MedicalService md on md.id=vms.id \n" +
"where d.id= :doctorId and v.status= :status and v.dateFrom>= :dateFrom and v.dateTo<= :dateTo")
List<VisitInfoWithPatientAndMedServices3joins> getAllVisitInfoWithPatientAndMedicalServicesJpqlQuery
(#Param("doctorId") Long doctorId, #Param("status") VisitStatus status, #Param("dateFrom") LocalDateTime dateFrom, #Param("dateTo") LocalDateTime dateTo, Pageable pageable);
And here is translated SQL from JPQL.
select doctor1_.id as col_0_0_, doctor1_.firstName as col_1_0_, doctor1_.lastName as col_2_0_, doctor1_.title as col_3_0_, doctor1_.email as col_4_0_, visit0_.id as col_5_0_, visit0_.dateFrom as col_6_0_, visit0_.dateTo as col_7_0_, visit0_.status as col_8_0_, medicalser4_.id as col_9_0_, medicalser4_.service as col_10_0_, medicalser4_.price as col_11_0_
from Visit visit0_
left outer join
(visit_medical_services medicalser2_ left outer join MedicalService medicalser3_ on medicalser2_.visit_id=medicalser3_.id) on visit0_.id=medicalser2_.medical_services_id
and (medicalser3_.id=visit0_.id)
left outer join Doctor doctor1_ on (visit0_.doctor_id=doctor1_.id)
left outer join MedicalService medicalser4_ on (medicalser4_.id=medicalser3_.id) where doctor1_.id=? and visit0_.status=? and visit0_.dateFrom>=? and visit0_.dateTo<=? limit ?
And the problem here is, that it's returning columns from #ManyToMany relations (visit_medical_services) but ONLY FOR THE FIRST OBJECT. Json response from Postman below:
[
{
"id": 1,
"status": "PAID",
"dateFrom": "2019-04-10T08:00:00",
"dateTo": "2019-04-10T08:30:00",
"medicalServicesId": 1,
"medicalServicesService": "Visit",
"medicalServicesPrice": 100.0,
"doctorLastName": "James",
"doctorFirstName": "Alex",
"doctorEmail": "james#gmail.com",
"doctorId": 1,
"doctorTitle": "dr n. md."
},
{
"id": 2,
"status": "PAID",
"dateFrom": "2019-04-10T09:00:00",
"dateTo": "2019-04-10T09:30:00",
"medicalServicesId": null,
"medicalServicesService": null,
"medicalServicesPrice": null,
"doctorLastName": "James",
"doctorFirstName": "Alex",
"doctorEmail": "james#gmail.com",
"doctorId": 1,
"doctorTitle": "dr n. md."
}
]
I tried to use translated SQL query using JPQL in Workbench, because I'm using MySQL database and the result is the same - first object is correct, and the rest have null values inside mapped #ManyToMany colums.
Here are my Entity classes if it would this issue a little bit easier:
public class Visit {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
LocalDateTime dateFrom;
LocalDateTime dateTo;
#Enumerated(EnumType.STRING)
VisitStatus status;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "doctor_id", referencedColumnName = "id", nullable = true)
#JsonManagedReference
Doctor doctor;
#ManyToOne(fetch = FetchType.LAZY)
#JsonManagedReference
#JoinColumn(name = "patient_id", referencedColumnName = "id", nullable = true)
Patient patient;
#ManyToMany
#JsonManagedReference
#JoinTable(
name = "visit_diseases",
joinColumns = #JoinColumn(
name = "disease_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(
name = "visit_id", referencedColumnName = "id"))
List<Disease> diseases;
#ManyToMany
#JsonManagedReference
#JoinTable(
name = "visit_medical_services",
joinColumns = #JoinColumn(
name = "medical_services_id"),
inverseJoinColumns = #JoinColumn(
name = "visit_id"))
Set<MedicalService> medicalServices;
String mainSymptoms;
String treatment;
String allergy;
String addiction;
String comment;
}
And Medical Services:
public class MedicalService {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
Long id;
String service;
Float price;
#ManyToMany(mappedBy = "medicalServices", fetch = FetchType.EAGER)
private Set<Visit> visits;
public MedicalService(Long id, String service, float price) {
this.id = id;
this.service = service;
this.price = price;
}
}
Can someone take a look please and explain to me what is not working correctly here? What i want to achive is to make JPQL generate THE SAME SQL query. It is even possible? Please help me...
You have a few errors in your query. Use the following instead
#Query("select d.id as doctorId, d.firstName as doctorFirstName, d.lastName as doctorLastName, d.title as doctorTitle, d.email as doctorEmail, " +
"v.id as id, v.dateFrom as dateFrom, v.dateTo as dateTo, v.status as status, md.id as medicalServicesId, md.service as medicalServicesService, md.price as medicalServicesPrice \n" +
"from Visit v \n" +
"left outer join v.doctor d \n" +
"left outer join v.medicalServices md \n"
"where d.id= :doctorId and v.status= :status and v.dateFrom>= :dateFrom and v.dateTo<= :dateTo")
List<VisitInfoWithPatientAndMedServices3joins> getAllVisitInfoWithPatientAndMedicalServicesJpqlQuery
(#Param("doctorId") Long doctorId, #Param("status") VisitStatus status, #Param("dateFrom") LocalDateTime dateFrom, #Param("dateTo") LocalDateTime dateTo, Pageable pageable);
This is the SQL query that returns the data I need:
SELECT
E.DESCS AS EMP, C.USERNAME,
(SELECT A.DESCS
FROM CAD_COLABORADOR H, CAD_DEPT A
WHERE H.DEPT = A.ID AND H.ID = C.ID) AS DEPT,
D.IDENTIFICADOR, D.MODELO, O.DESCS AS OFFICE,
D.K_OFFICE AS 'KEY OFFICE', S.DESCS AS SO, D.K_SO AS 'KEY SO'
FROM
IN_DESKTOP D
LEFT OUTER JOIN
CAD_COLABORADOR C ON D.ID = C.DESKTOP
INNER JOIN
CAD_EMP E ON D.EMP = E.ID
INNER JOIN
CAD_OFFICE O ON D.V_OFFICE = O.ID
INNER JOIN
CAD_SO S ON D.V_SO = S.ID ;
This is the linq expression I'm using plus has some inconsistencies since it returns the most data are not exactly the same as the SQL query:
var result = from desk in db.IN_DESKTOP
join co in db.CAD_COLABORADOR on desk.id equals co.id into egroup
from co in egroup.DefaultIfEmpty()
join e in db.CAD_EMP on desk.emp equals e.id
join o in db.CAD_OFFICE on desk.v_office equals o.id
join s in db.CAD_SO on desk.v_so equals s.id
select new
{
Empresa = e.descs,
UserName = co.username,
Departamento = co.CAD_DEPT.descs,
Identificador = desk.identificador,
Modelo = desk.modelo ,
Offices = o.descs,
KeyOfice = desk.k_office,
KeySo = desk.k_so
};
A left outer join in C# is just a GroupJoin followed by a SelectMany with default if empty - I've been using this extension for lambda expressions
public static class LinqExtension
{
public static IEnumerable<TResult> LeftOuterJoin<TLeft, TRight, TKey, TResult>(
this IEnumerable<TLeft> leftCollection, IEnumerable<TRight> rightCollection,
Func<TLeft, TKey> leftKey, Func<TRight, TKey> rightKey,
Func<TLeft, TRight, TResult> result)
{
return leftCollection.GroupJoin(rightCollection,
leftKey,
rightKey,
(leftObject, rightObject) => new { leftObject, rightObject })
.SelectMany(x => x.rightObject.DefaultIfEmpty(),
(l, r) => new { left = l.leftObject, right = r })
.Select(x => result.Invoke(x.left, x.right));
}
}
select
count(pat.ID) as PatientEmail,
count(a.ID) as AlaEmails,
count(t.ID) as TrusteeEmails,
count(s.ID) + 1 as SpecialistEmail
from [dbo].[Users] as u
left join [dbo].[Patients] as pat
on u.ID = pat.ID and u.Email != 'email#gmail.com'
left join [dbo].[Patients] as a
on u.ID = a.ID and u.Email = 'email#gmail.com'
left join [dbo].[Trusteehips]as t
on u.ID = t.Trustee_ID
left join [dbo].[Specialists] as s
on u.ID = s.ID and u.Email != 'email#gmail.com'
where u.Active = 1 and u.Deleted = 0
public class UserEmails
{
public int PatientEmail { get; set; }
public int AlaEmails { get; set; }
public int TrusteeEmails { get; set; }
}
public ActionResult ReportByEmail()
{
var res = from u in context.Users
join p in context.Patients
on u.ID equals p.ID into pGroup
join t in context.Trusteeships
on u.ID equals t.Trustee.ID into tGroup
select new UserEmails
{
PatientEmail = pGroup.Count(g => g.Email != "email#gmail.com"),
AlaEmails = pGroup.Count(g => g.Email = "email#gmail.com"),
TrusteeEmails = tGroup.Count()
};
return View(res);
I tried to write this Linq code but it didn't work!
My count result is not shown in one row, I wrote code with same syntax (Group.Count()) and it worked fine, but here it didn't work!
How can I write the following SQL in LINQ to Entities?
SELECT r.rolename,
( CASE
WHEN ur.username IS NULL THEN 0
ELSE 1
END ) AS isinrole
FROM bgt.roles r
LEFT OUTER JOIN bgt.usersinroles ur
ON ur.rolename = r.rolename
AND ur.username = 'ADMIN'
This worked for me. Thanks for all the suggestions.
var query =
from r in Roles
from ur in UsersInRoles
.Where(v => v.Rolename == r.Rolename && v.Username == "ADMIN")
.DefaultIfEmpty()
select new { Rolename = r.Rolename, IsInRole = (ur.Username != null) };
The generated SQL is as follows
SELECT
1 AS [C1],
[Extent1].[Rolename] AS [Rolename],
CASE WHEN ([Extent2].[Username] IS NOT NULL) THEN cast(1 as bit) WHEN ([Extent2].[Username] IS NULL) THEN cast(0 as bit) END AS [C2]
FROM [bgt].[Roles] AS [Extent1]
LEFT OUTER JOIN [bgt].[UsersInRoles] AS [Extent2] ON ([Extent2].[Rolename] = [Extent1].[Rolename]) AND ('ADMIN' = [Extent2].[Username])
I would do it like this:
from role in db.Roles
let isInRole = role.UsersInRoles.Any(u => u.UserName == "ADMIN")
select new { role.RoleName, isInRole }
Althought the generated SQL is not as nice as yours.
Extension method for Left join (linq to entities):
public static class DbSetExtensions
{
public static IQueryable<TResult2> LeftJoin<TOuter, TInner, TKey, TResult2>(
this IQueryable<TOuter> outerList,
IEnumerable<TInner> innerList,
Expression<Func<TOuter, TKey>> outerKeySelector,
Expression<Func<TInner, TKey>> innerKeySelector,
Expression<Func<LeftJoinTemp<TOuter, TInner>, TInner, TResult2>> resultSelector2)
{
// (tr, historicPrices) => new { tr, historicPrices }
Expression<Func<TOuter, IEnumerable<TInner>, LeftJoinTemp<TOuter, TInner>>> myResultSelector1
= (tr, historicPrices) => new LeftJoinTemp<TOuter, TInner> { outer = tr, inners = historicPrices };
// e => e.historicPrices.DefaultIfEmpty()
Expression<Func<LeftJoinTemp<TOuter, TInner>, IEnumerable<TInner>>> myCollectionSelector
= e => e.inners.DefaultIfEmpty();
//var a = outerList.GroupJoin(innerList, outerKeySelector, innerKeySelector, resultSelector1);
var a = outerList.GroupJoin(innerList, outerKeySelector, innerKeySelector, myResultSelector1);
//return a.SelectMany(collectionSelector, resultSelector2);
var b = a.SelectMany(myCollectionSelector, resultSelector2);
return b;
}
}
public class LeftJoinTemp<TOuter, TInner>
{
public TOuter outer;
public IEnumerable<TInner> inners;
}
example calling, left join of Transaction and HistoricPrice, for transaction you have to write parent.outer
.LeftJoin(db.HistoricPrices,
transaction => new { transaction.InstrumentId, DateId = transaction.Date2Id },
historicPrice => new { historicPrice.InstrumentId, historicPrice.DateId },
(parent, historicPrice) => new
{
parent.outer.Id,
parent.outer.OpeningDate,
parent.outer.InstrumentName,
historicPrice.DateId,
historicPrice.InstrumentId
})