Entity Framework Linq to SQL expression containing LEFT JOIN - sql

I'm attempting to translate some T-SQL to an Entity Framework Core lambda expression. It involves an inner join and a left joing with a where clause.
Here is the working SQL query:
SELECT
AspNetUsers.*, Exclusions.*
FROM
AspNetUsers
JOIN Exclusions ON
AspNetUsers.FirstName = Exclusions.FirstName
AND AspNetUsers.LastName = Exclusions.LastName
LEFT JOIN ExclusionsMatches ON
ExclusionsMatches.RowHash = Exclusions.RowHash
WHERE
ExclusionsMatches.MatchIgnoredByUserId IS NULL
Which I have thus far translated into LINQ lambda as such:
var result = _db.Users
.Join(_db.Exclusions, usr => new { usr.FirstName, usr.LastName }, Exc => new { Exc.FirstName, Exc.LastName }, (usr, Exc) => new { usr, Exc })
.GroupJoin(_db.ExclusionsMatches, i => i.Exc.RowHash, x => x.RowHash, (i, ExcMatch) => new { User = i.usr, Exc = i.Exc, ExcMatch = ExcMatch })
.SelectMany(temp => temp.ExcMatch.DefaultIfEmpty(), (temp, p) => new { User = temp.User, Exc = temp.Exc, ExcMatch = temp.ExcMatch})
This seems to give me the desired query output, but I can't seem to figure out how to get the WHERE ExclusionsMatches.MatchIgnoredByUserId IS NULL clause translated.
Any thoughts on how the WHERE might be achieved? I'm also open to changing from lambda expression to linq query expression.
Thanks!

I believe using LINQ is more readable so I can provide an answer using LINQ as below.
from user in _db.Users
join excl in _db.Exclusions on new { usr.FirstName , usr.LastName} equals {excl.FirstName , excl.LastName}
join exclMtch in _db.ExclusionsMatches on excl.RowHash equals exclMtch.RowHash into grp
from itm in grp.DefaultIfEmpty()
where itm.MatchIgnoredByUserId == null
select new {
user,
excl
}
Otherwise, if you insist on using Lambda, first you have to select the field in your final selects and then add the needed where in the end of query.
var result = _db.Users
.Join(_db.Exclusions, usr => new { usr.FirstName, usr.LastName }, Exc => new { Exc.FirstName, Exc.LastName }, (usr, Exc) => new { usr, Exc })
.GroupJoin(_db.ExclusionsMatches, i => i.Exc.RowHash, x => x.RowHash, (i, ExcMatch) => new { User = i.usr, Exc = i.Exc, ExcMatch = ExcMatch MatchIgnoredByUserId = i.MatchIgnoredByUserId })
.SelectMany(temp => temp.ExcMatch.DefaultIfEmpty(), (temp, p) => new { User = temp.User, Exc = temp.Exc, ExcMatch = temp.ExcMatch, MatchIgnoredByUserId= temp.MatchIgnoredByUserId })
.Where(q => q.MatchIgnoredByUserId == null )
Do not forget to track your query in SQL Profiler :)

Related

how to add conditional where parameters to sql query in node js

I have the below method that aims to filter records from a table. But sometimes, the user might only select one filter or two. I want to add where conditions only for parameters that the user sends. At the moment, it filters with all conditions. One possibility I know is to use some conditions to concatenate the string if true but I do not think this is the best way.
Any better way of doing this?
// Retrieve hotels by filter
app.get('/filter', (request, response) => {
var name = request.query.name;
var country = request.query.country;
var freeWifi = request.query.freeWifi;
var freeParking = request.query.freeParking;
var restaurant = request.query.restaurant;
var pool = request.query.pool;
var gym = request.query.gym;
var airconditioning = request.query.airconditioning;
let query = `select * from hotels h inner join hotelFilters hf on h.id = hf.hotelId where h.title like "%${isNullOrUndefined(name) ? '' : name}%"
and hf.freeWifi = ${freeWifi} and hf.freeParking = ${freeParking} and hf.restaurant = ${restaurant} and hf.outdoorPool = ${pool}
and hf.airConditioning = ${airconditioning}
and hf.gym = ${gym}`;
connection.query(query, (error, result) => {
if (error) {
console.log(error, 'Error occurred with hotels/filter API...');
}
if (result.length > 0) {
response.send({
result
})
}
})
});

Is it possible in PostgreSQL to do one query to get the result of object inside object?

At this moment I do query like this :
static async getAllAppointmentSerivce () {
// Get all appointment with detail
const query = {
name: 'getAllAppointment',
text: 'SELECT app.id, cus.name as name, cus.email as email, app.date, app.status, app.link FROM appointments app INNER JOIN admins adm ON app.admin_id = adm.id INNER JOIN customers cus ON app.customer_id = cus.id ORDER BY id ASC'
}
return pool.query(query)
.then(async res => {
for (let i = 0; i < res.rows.length; i++) {
const admin = await AdminService.getAdminDetailByAppointmentId(res.rows[i].id)
res.rows[i].admin = admin
}
return res.rows
})
.catch(err => console.log(err.stack))
}
And the result is like this :
Query result
My question is, is that possible to do that in a single query?

Nhibernate SQLQuery as Subquery

How Can use a native sqlquery (session.CreateSqlQuery) as filtering subquery in another QueryOver:
// Get ids
var idsq = _session.CreateSQLQuery(
"select Id from [dbo].[SomeFunction](:parameter)")
.AddEntity(typeof(long)).
SetParameter("parameter", folderId);
// get entities by filtering where in (subquery)
MyEntity entityAlias = null;
var listOfEntities = await _session.QueryOver(() => entityAlias).
Where(x=>x.Id).IsIn(idsq).
OrderBy(x => x.Name).Asc.
ListAsync(cancelToken).ConfigureAwait(false);
You can't easily mix various styles of NHibernate... What you can do:
var crit = new SQLCriterion(SqlString.Parse("{alias}.Id IN (select Id from [dbo].[SomeFunction](?))"),
new object[] { folderId },
new IType[] { NHibernateUtil.Int64 });
and then:
var listOfEntities = await _session.QueryOver(() => entityAlias)
.Where(crit)
.OrderBy(x => x.Name).Asc
Note how I changed the text query adding {alias}.Id IN (...)

translating sql statement to linq

I have a working sql statement and want it as linq statement or linq methode chain.
My statement is:
SELECT T1.*
FROM (SELECT Col1, MAX(InsertDate) as Data
FROM Zugbewegungsdaten
GROUP BY Loknummer) as temp JOIN T1
ON (T1.Col1= temp.Col1
AND Zugbewegungsdaten.InsertDate= temp.Date)
WHERE Col3=1
ORDER BY Loknummer
Can anybody help me to translate it?
Edit after comment:
Ok, my result for the inner select:
var maxResult = (from data in context.T1
group data by data.Col1
into groups
select new
{
Train = groups.Key,
InsertDate= groups.Max( arg => arg.InsertDate)
}) ;
I tried the join like this:
var joinedResult = from data in context.T1
join gdata in maxResult on new
{
data.Col1,
data.InsertDate
}
equals new
{
gdata.Col1,
gdata.InsertDate
}
select data;
But i get a compiler error by the join that the typeargument are invalid.
In the case that the join works i whould use a where to filter the joinedResult.
var result = from data in joinedResult
where data.Col3 == true
select data;
After much more "try and error", I got this version it looks like it works.
var joinedResult = ( ( from data in context.T1
group data by data.Col1
into g
select new
{
Key= g.Key,
Date = g.Max( p => p.InsertDate)
} ) ).Join( context.T1,
temp => new
{
Key = temp.Key,
InsertDate = temp.Date
},
data => new
{
Key = data.Col1,
InsertDate = data.InsertDate
},
( temp,
data ) => new
{
temp,
data
} )
.Where( arg => arg.data.Col3)
.OrderBy( arg => arg.data.Col1)
.Select( arg => arg.data );
Could it be that i have to set the same property names (Key, InsertDate) by joins over multi columns?

LINQ Where Exists GROUP BY

How can i convert this in LINQ?
SELECT B.SENDER, B.SENDNUMBER, B.SMSTIME, B.SMSTEXT
FROM MESSAGES B
WHERE EXISTS ( SELECT A.SENDER
FROM MESSAGES A
WHERE A.SENDER = B.SENDER
GROUP BY A.SENDER
HAVING B.SMSTIME = MAX( A.SMSTIME))
GROUP BY B.SENDER, B.SENDNUMBER, B.SMSTIME, B.SMSTEXT ;
Thanks a lot :)
EDIT!!
Resolved with:
var Condition = "order by SMSTime desc";
IEnumerable<ClassMessaggio> messaggi = Database.Select<ClassMessaggio>(Condition);; // Load all but sorted
ElencoConversazioni = messaggi.GroupBy(m => new { m.Number })
.Select(g => g.OrderByDescending(m => m.SMSTime).First()).ToObservableCollection();
Try
db.Messages.Where(b => b.SmsTime == Messages.Where(a => a.Sender == b.Sender)
.Max(a => a.SmsTime))
Or
db.Messsages.GroupBy(m => new { m.Sender, m.SendNumber })
.Select(g => g.OrderByDescending(m => m.SmsTime).First())
Where db is your DataContext.
To show the list of conversations along with "the last message of every contact", you could try something like:
// a query to find the last Sms time per sender
var lastSmsQuery = from m in db.messages
group m by m.Sender into grouping
select new
{
Sender = grouping.Key,
LastSmsTime = grouping.Max(x => x.SmsTime)
};
// a query to find the messages linked to the last Sms per sender
var lastMessageQuery = from m in db.messages
join l in lastSmsQuery on new { m.Sender, m.SmsTime } equals new { l.Sender, l.LastSmsTime }
select m;
The 2-query method used is similar to that of this question from earlier today - Convert SQL Sub Query to In to Linq Lambda