Entity Framework join query with int array - sql

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

Related

How do i convert this SQL to Entity Framework LINQ query

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; }

generate mysql query from relations using via or viaTable relations

consider the below example...
class Customers extends ActiveRecord
{
public function getOrders()
{
return $this->hasMany(Orders::className(), ['customer_id' => 'id']);
}
public function getOrderItems()
{
return $this->hasMany(OrderItems::className(), ['order_id' => 'id'])
->via('orders');
}
}
how i can generate any one of the follwing query from the getOrderItems() relation
SELECT * FROM `order-items`
LEFT JOIN `orders` ON `orders`.`id` = `order-items`.`order_id`
LEFT JOIN `customers` ON `customer`.`id` = `orders`.`customer_id`
OR
SELECT `order-items`.* FROM `order-items`,`orders`,`customers`
WHERE `customer`.`id` = `orders`.`customer_id` AND `orders`.`id` = `order-items`.`order_id`
OR
SELECT * FROM `order-items` WHERE `order_id` IN(
SELECT * FROM `orders` WHERE `customer_id` IN(
SELECT * FROM `customers`
)
)
i use the following code to do this.
$customers = Customers::findAll();
$query = $customers[0]->getOrderItems()->createCommand()->rawSql;
but it only generates
SELECT * FROM `order-items`
What to do...???
use this :
$q = Customers::findAll()->innerJoinWith('orderItems')->createCommand()->rawSql;
you have to use relation name like this not as function

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
};

Query syntax in entity framework

I'm doing a query (see below), but I do not know how to retrieve all data from a select.
var model = new dbContext();
var query = from mp in model.matiere_premiere join req in (from stk in model.stock_mp
join ms in model.matiere_premiere
on stk.matiere_premiere_code equals
ms.code
where stk.date <= DateTime.Today
orderby stk.date descending
select new new { stk.qte, stk.matiere_premiere_code })
on mp.code equals req.matiere_premiere_code
group mp by new { mp.code } into grp
orderby grp.Key
select new
{
grp.Key,
grp.First().designation,
grp.Last().frns
};
The equivalent sql query is:
SELECT matiere_premiere.code,matiere_premiere.designation,
"matiere_premiere.unite, matiere_premiere.frns ,IF(ISNULL(REQ.qte), '0.00', REQ.qte) AS qte
FROM matiere_premiere LEFT JOIN (SELECT qte,matiere_premiere_code FROM stock_mp
JOIN matiere_premiere ON matiere_premiere.code = matiere_premiere_code
WHERE DATE <= CURRENT_DATE() ORDER BY DATE DESC)
AS REQ ON REQ.matiere_premiere_code = matiere_premiere.code
GROUP BY matiere_premiere.code ORDER BY matiere_premiere.code
it's simple, the group is also an enumerator, so you should return
select grp;
then, for each group, you can do a foreach of the values
foreach(var group in query)
{
Console.WriteLine("Key: " + group.Key);
foreach(var v in group)
{
Console.WriteLine("Value: " + v.Property);
}
}

Linq To Sql, Sum and main and joined table

My linq query
from report in CustomerDayReports
join payments in CustomerPayments on new { report.CustomerId, report.CurrencyId } equals new { payments.CustomerId, payments.CurrencyId } into j
from j2 in j.DefaultIfEmpty()
group report by new { report.CustomerId, report.CurrencyId } into g1
select new
{
Customer = g1.Key.CustomerId,
Currency = g1.Key.CurrencyId,
Debt = g1.Sum(x => x.Value * x.Amount)
}
Result SQL
SELECT
SUM([t0].[Value] * [t0].[Amount]) AS [Debt],
[t0].[CustomerId] AS [Customer],
[t0].[CurrencyId] AS [Currency]
FROM [CustomerDayReport] AS [t0]
LEFT OUTER JOIN [CustomerPayment] AS [t1]
ON ([t0].[CustomerId] = [t1].[CustomerId]) AND ([t0]. [CurrencyId] = [t1].[CurrencyId])
GROUP BY [t0].[CustomerId], [t0].[CurrencyId]
How modify linq for get next SQL?
*SUM([t0].[Value] * [t0].[Amount])*
to
*T0.SUM([t0].[Value] * [t0].[Amount])* - ISNULL(SUM([T1].Amount)
SELECT
SUM([t0].[Value] * [t0].[Amount]) - ISNULL(SUM([t1].Amount), 0) AS [Debt],
[t0].[CustomerId] AS [Customer],
[t0].[CurrencyId] AS [Currency]
FROM [CustomerDayReport] AS [t0]
LEFT OUTER JOIN [CustomerPayment] AS [t1]
ON ([t0].[CustomerId] = [t1].[CustomerId]) AND ([t0]. [CurrencyId] = [t1].[CurrencyId])
GROUP BY [t0].[CustomerId], [t0].[CurrencyId]
Correct grouping is
group new {report, payments} by new { report.CustomerId, report.CurrencyId } into g
All query is
from report in CustomerDayReports
join payments in CustomerPayments on new { report.CustomerId, report.CurrencyId } equals new { payments.CustomerId, payments.CurrencyId } into j
from payments in j.DefaultIfEmpty()
group new {report, payments} by new { report.CustomerId, report.CurrencyId } into g
select new
{
Customer = g.Key.CustomerId,
Currency = g.Key.CurrencyId,
Debt = g.Sum(x => x.report.Value * x.report.Amount) - ((decimal?) g.Sum(x => x.payments.Amount) ?? (decimal?)0)
}