How do i convert this SQL to Entity Framework LINQ query - sql

Can someone help me convert this SQL Query to EntityFramework LINQ?
DECLARE #UserId varchar(50) = '123'
SELECT
TL.TrackId,
COUNT(*) AS LikeCount,
(SELECT IIF(COUNT(*) > 0, 'true','false') FROM UserTrackLikes WHERE
UserId = #UserId AND TrackId = TL.TrackId) AS IsLiked
FROM TrackList AS TL
LEFT OUTER JOIN UserTrackLikes AS UTL
ON UTL.TrackId = TL.TrackId
GROUP BY TL.TrackId

You can use the query syntax:
int userId = 123;
var result = (from trackList in context.TrackLists
select new
{
trackList.TrackId,
LikeCount = trackList.Likes.Count(),
IsLiked = trackList.Likes.Any(x => x.UserId == userId)
}).ToList();
Assuming that here, Likes is a collection of UserTrackLike, declared like this:
public ICollection<UserTrackLike> Likes { get; set; }

Related

Linq to SQL use case and Lag equivalent

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();

select some ids from sql in linq

hi I'm using the query below to select studentId and Score from table1 now i want select users that i selected their ids from table2, how i can select it with ids?
i can select users with this query from v in dc.tbl_Students select v but i want select some users that i have their id.
var qBestMan = (from T in (((from tbl_ActPoints in dc.tbl_ActPoints
select new
{
StudentId = (int?)tbl_ActPoints.StudentId,
Score = (int?)tbl_ActPoints.Score
}).Concat(
from tbl_EvaPoints in dc.tbl_EvaPoints
select new
{
StudentId = (int?)tbl_EvaPoints.StudentId,
Score = (int?)tbl_EvaPoints.Score
})))
group T by new
{
T.StudentId
} into g
orderby g.Sum(p => p.Score) descending
select new
{
g.Key.StudentId,
HighScoreUser = g.Sum(p => p.Score)
}).ToArray();
Try something like this:
//qBestMan must be a List, or a IEnumarable and not a Array. Remove the .ToArray() at the end, or substitute it by .ToList()
var Result = from users in dc.tbl_Students
join bestMen in qBestMan on bestMen.StudentId equals users.userid
select new
{
//fields that you want
example = users.example,
other = bestMen.other
};

Entity Framework join query with int array

i have got 3 tables on my database.
---Student---
id - name
---Language---
id - lang
---StudentLanguage---(Common Table)
id - studentId - langId
Students can have more languages. i want to search students with an int[] array values. But not with IN() - Contains(), it must be with and - && operator and this operator take int[] values.
in sql =
`select t1.id, t1.name from Student t1 join StudentLanguage t2
ON(t1.id=t2.studentId) where (t2.langId=1 and t2.langId=3 and t2.langId=5);`
so how can i do this query with Entity Framework? (...where new int[] { 1,3,5 })
This code generate some clumsy sql query...
int[] ids = new[] { 1, 3, 5 };
var acc = from st in db.Students select st;
foreach (var id in ids)
{
int id1 = id;
var res =
from st in db.Students
from lng in st.Language
where lng.Id == id1
select st;
acc =
from a in acc
join st in res on a.Id equals st.Id
select a;
}
acc.ToList();
... sql query :
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name]
FROM [dbo].[Student] AS [Extent1]
INNER JOIN [dbo].[StudentLanguage] AS [Extent2] ON [Extent1].[Id] = [Extent2].[Student_Id]
INNER JOIN [dbo].[StudentLanguage] AS [Extent3] ON [Extent1].[Id] = [Extent3].[Student_Id]
INNER JOIN [dbo].[StudentLanguage] AS [Extent4] ON [Extent1].[Id] = [Extent4].[Student_Id]
WHERE ([Extent2].[Language_Id] = #p__linq__0)
AND ([Extent3].[Language_Id] = #p__linq__1)
AND ([Extent4].[Language_Id] = #p__linq__2)
List<int> langIds = new int[] { 1, 3, 5 }.ToList();
var c = langIds.Count;
var res2 = _context.Students
.Where(x => x.StudentLanguages
.Where(l => langIds.Contains(l.langId)).Select(y => y.langId).Distinct().Count() >= c);
result SQL:
SELECT [t0].[id], [t0].[name]
FROM [dbo].[Student] AS [t0]
WHERE ((
SELECT COUNT(*)
FROM (
SELECT DISTINCT [t1].[langId]
FROM [dbo].[StudentLanguage] AS [t1]
WHERE ([t1].[langId] IN (1, 3, 5)) AND ([t1].[studentId] = [t0].[id])
) AS [t2]
)) >= 3
Use Distinct if StudentLanguages theoretically may have several overlapping bundles StudentId - LangId.
Try something like this...
resultArr = [];
For(int i = 0; i<arr.length; i++) {
var result = db.Student.Where(s=>s.StudentLanguage.langId == arr[i]);
resultArr.append(result);
}
var db = new MyDbContext();
var langIds = new[] { 1, 3, 5 };
IEnumerable<Student> student = from st in db.student select st;
foreach (var item in langIds)
{
student = student.Join(db.StudentLanguage.Where(w => w.langId == item),
st => st.studentId,
stMap => stMap.id,
(st, stMap) => new { Student= stMap, StudentLanguage = st})
.Select(x => x.Student).Distinct();
}
i can do this like that. Maybe foreach can be turn linq and this code can be only one line and a little short.
I try to search how to do it and here is what i come out with:
int[] langIds = new int[] { 1, 3, 5 };
var lang = _context.Languages.Where(x => langIds.Contains(x.id));
var result = _context.Students.Where(x => !lang
.Except(x.StudentLanguages
.Select(y => y.Language)
.Intersect(lang)).Any());
Here i use Except and Intersect linqToSQL extension methods.
It produces this SQL statement:
SELECT [t0].[id], [t0].[name]
FROM [dbo].[Student] AS [t0]
WHERE NOT (EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT DISTINCT [t1].[id], [t1].[name]
FROM [dbo].[Language] AS [t1]
WHERE (NOT (EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT DISTINCT [t3].[id], [t3].[name]
FROM [dbo].[StudentLanguage] AS [t2]
INNER JOIN [dbo].[Language] AS [t3] ON [t3].[id] = [t2].[langId]
WHERE (EXISTS(
SELECT NULL AS [EMPTY]
FROM [dbo].[Language] AS [t4]
WHERE ([t3].[id] = [t4].[id]) AND ([t4].[id] IN (#p0, #p1, #p2))
)) AND ([t2].[studentId] = [t0].[id])
) AS [t5]
WHERE [t1].[id] = [t5].[id]
))) AND ([t1].[id] IN (#p3, #p4, #p5))
) AS [t6]
))
Note that i populate languages from database. Unfortunatly you can not use local collections in your query since LinqToSQL don't know how to translate them into SQL. If you do the same thing with local int array or any other collection you will get this exception:
LINQ To SQL exception: Local sequence cannot be used in LINQ to SQL
implementation of query operators except the Contains operator

How can I count results from one into a group with different conditions? Linq query

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 to select from a subselect on NHibernate

How can I map this SQL using NHibernate Criteria API?
Sql:
SELECT COUNT(*) FROM (
SELECT FirstName, LastName FROM Employees GROUP BY FirstName, LastName
) AS Query
This is a very very simple query, my query has a SubSelect much more complex.
So, any idea?
I found a solution for the question, it's a very big hack but it works as expected.
I had to get the generated SQL and surround it with the SELECT COUNT(*) query. Here is the code to do that:
public ISQLQuery BuildCountQuery(ICriteria criteria)
{
CriteriaImpl c = (CriteriaImpl)criteria;
SessionImpl s = (SessionImpl)c.Session;
string entityOrClassName = ExtractRealClassName(c);
SessionFactoryImpl factory = (SessionFactoryImpl)s.SessionFactory;
String[] implementors = factory.GetImplementors(entityOrClassName);
string implementor = implementors.Length == 0 ? null : implementors[0];
var persister = (IOuterJoinLoadable)factory.GetEntityPersister(implementor);
CriteriaLoader loader = new CriteriaLoader(persister, factory, c, implementor, s.EnabledFilters);
SqlString sql = loader.SqlString.Insert(0, "SELECT COUNT(*) FROM (");
sql = sql.Append(") AS Query");
var parameters = loader.Translator.CollectedParameters;
var sqlQuery = this.session.CreateSQLQuery(sql.ToString());
for (int i = 0; i < parameters.Count; i++)
sqlQuery.SetParameter(i, parameters.ElementAt(i).Value, parameters.ElementAt(i).Type);
return sqlQuery;
}
private string ExtractRealClassName(CriteriaImpl criteria)
{
Type rootEntityType = criteria.GetRootEntityTypeIfAvailable();
if (rootEntityType.GetInterfaces().Contains(typeof(INHibernateProxy)))
return criteria.GetRootEntityTypeIfAvailable().BaseType.FullName;
else
return criteria.EntityOrClassName;
}
DetachedCriteria criteriaEmployees = DetachedCriteria.For<Employees>();
criteriaEmployees.SetProjection(Projections.CountDistinct("FirstName"));
ICriteria executableCriteria = criteriaEmployees.GetExecutableCriteria(Session);
int count = executableCriteria.UniqueResult<int>();
DetachedCriteria can be used to create subqueries. Some examples are in the documentation.