Nested Query Entity Framework - entity-framework

Need help in converting below SQL nested query to a LINQ query?
select P.ProductId, P.Name, C.Name, I.Image
from Product P
join ProductImage I on P.ProductId = I.ProductId
join ProductCategory C on P.Category = C.CategoryId
where P.ProductId in (select distinct ProductId
from ProductVariantMapping M
where M.GUID in (select top 3 V.Guid
from [Order] O
join Inventory V on V.InventoryId = O.InventoryId
group by O.InventoryId, V.Guid
order by Sum(O.Quantity) desc))
Below is my attempt in converting to LINQ query :
var a = (from product in ekartEntities.Products
join productImage in ekartEntities.ProductImages
on product.ProductId equals productImage.ProductId
join category in ekartEntities.ProductCategories
on product.Category equals category.CategoryId
where product.ProductId
select new ProductDTO()
{
ProductId = product.ProductId,
Name = product.Name,
Category = category.Name,
Image = productImage.Image
}).ToList();
what is the equivalent of "IN" when converting to LINQ .
I got the solution for 'IN' clause.
But how do I use sum(Quantity) in order by after grouping?
I am new to Entity Framework. Can anyone help me?

In LINQ, you will need to use the "contains()" method to generate the 'IN' You need to put a list in the Contains method. If sends a query, that query will be repeated for completions and this will lead to performance loss.
Sample:
var sampleList = (from order ekartEntities.Order
join inventory in ekartEntities.Inventory on order.InventoryId equals inventory.InventoryId
select order).toList();
var query = (from product in ekartEntities.Products
join productImage in ekartEntities.ProductImages
on product.ProductId equals productImage.ProductId
join category in ekartEntities.ProductCategories
on product.Category equals category.CategoryId
where sampleList.Contains(product.ProductId)
select new ProductDTO()
{
ProductId = product.ProductId,
Name = product.Name,
Category = category.Name,
Image = productImage.Image
}).ToList();

Do not apply ToList() in the first query
I made some test.
Test 1 (with my own data):
var phIds = new List<string>
{
//List of Ids
};
using (var db = new ApplicationDbContext())
{
var studentsId = db.Relations
.Where(x => phIds.Contains(x.RelationId))
.Select(x => x.Id)
.Distinct(); //IQueryable here
var studentsQuery = from p in db.Students
where studentsId.Contains(p.Id)
select p;
var students= studentsQuery .ToList();
}
The generated query looks like :
SELECT
[Extent1].[Id] AS [Id],
[...]
FROM [dbo].[Students] AS [Extent1]
WHERE EXISTS (SELECT
1 AS [C1]
FROM ( SELECT DISTINCT
[Extent2].[StudentId] AS [StudentId]
FROM [dbo].[Relations] AS [Extent2]
WHERE ([Extent2].[RelationId] IN (N'ccd31c3d-dfa3-4b40-...', N'd2cb05a2-ece3-4060-...'))
) AS [Distinct1]
WHERE [Distinct1].[StudentId] = [Extent1].[Id]
)
The query looks exactly like I wanted
However, if you add the ToList() in the first query to get the ids, you no longer have an IQueryable but a list.
Test 2 : wrong (I added ToList):
var phIds = new List<string>
{
//List of Ids
};
using (var db = new ApplicationDbContext())
{
var studentsId = db.Relations
.Where(x => phIds.Contains(x.RelationId))
.Select(x => x.Id)
.Distinct().ToList(); // No longer IQueryable but a list of 3000 int
var studentsQuery = from p in db.Students
where studentsId .Contains(p.Id)
select p;
var students= studentsQuery .ToList();
}
The generated query is ugly:
SELECT
[Extent1].[Id] AS [Id],
[...]
FROM [dbo].[Patients] AS [Extent1]
WHERE [Extent1].[Id] IN (611661, 611662, 611663, 611664,....
//more than 3000 ids here
)

Related

Select FROM Subquery without starting with another context object

I am trying to model the following MSSQL query that I am trying to replicate in netCore 2.2 - EF Core:
SELECT
wonum,
MIN(requestdate) AS startdate,
MAX(requestdate) AS enddate,
MIN(laborcode)
FROM
(
SELECT
wo.wonum,
sw.requestdate,
wo.wolablnk AS 'laborcode'
FROM
DB1.dbo.web_users wu INNER JOIN
DB2.dbo.workorder wo on
wu.laborcode = wo.wolablnk INNER JOIN
DB2.dbo.sw_specialrequest sw on
wo.wonum = sw.wonum
WHERE
wo.status in ('LAPPR', 'APPR', 'REC') AND
sw.requestdate > GETDATE()
) a
GROUP BY
wonum
ORDER by
I have the subquery portion built and working but that leaves me at an impasse:
var workOrders = await _db1Context.Workorder
.Where(r => r.Status == "LAPPR" || r.Status == "APPR" || r.Status == "REC")
.ToListAsync();
var specialRequests = await _db2Context.SwSpecialRequest
.Where(r => r.Requestdate > DateTime.Now)
.ToListAsync();
var subQuery = (from webUser in webUsers
join workOrder in workOrders on webUser.Laborcode equals workOrder.Wolablnk
join specialRequest in specialRequests on workOrder.Wonum equals specialRequest.Wonum
orderby webUser.Laborcode, specialRequest.Requestdate, specialRequest.Wonum
select new { workOrder.Wonum, Laborcode = workOrder.Wolablnk, specialRequest.Requestdate, workOrder.Workorderid })
.ToList();
I am not sure how to initiate the query I need with the subquery i've built and i'm not sure if I am on the right track even. I've looked at a couple of other examples but i'm not getting it.
Would anyone be able to shed some light on the subject and help?
Thank you!
Write LINQ query identical to the SQL and do not mix with ToListAsync(). After ToListAsync() query is sent to the server. Also you should use only one DbContext for such query.
var webUsers = _db1Context.Webuser;
var workOrders = _db1Context.Workorder
.Where(r => r.Status == "LAPPR" || r.Status == "APPR" || r.Status == "REC");
var specialRequests = _db1Context.SwSpecialRequest
.Where(r => r.Requestdate > DateTime.Now);
var subQuery =
from webUser in webUsers
join workOrder in workOrders on webUser.Laborcode equals workOrder.Wolablnk
join specialRequest in specialRequests on workOrder.Wonum equals specialRequest.Wonum
select new
{
workOrder.Wonum,
Laborcode = workOrder.Wolablnk,
specialRequest.Requestdate
};
var resultQuery =
from a in subQuery
group a by a.Wonum into g
select new
{
Wonum = g.Key,
StartDate = g.Min(x => x.Requestdate),
EndDate = g.Max(x => x.Requestdate),
Laborcode = g.Min(x => x. Laborcode)
};
// final materialization
var result = await resultQuery.ToListAsync();

LINQ - Conditional Join

I have a condition where joining table have a condition. Let's say I have a table called Mapper Student Teacher where Mapper table have a column named AcNoId which contains a id from both table Student and Teacher. The table structure is
Mapper
Student
Teacher
TestOption is a enum and is defined as a
public enum TestOption
{
Teacher = 1,
Student = 2
}
Now I have a condition where if TestOption is a type of Student it should perform a join with Student table and if is a type of Teacher it should perform a join with Teacher table
This is how I have tried so far
(from m in _context.Mapper
where m.TestOption == TestOption.Student
join s in _context.Student
on m.AcNoId equals s.Id into tempStudent
from st in tempStudent.DefaultIfEmpty()
where m.TestOption == TestOption.Teacher
join t in _context.Teacher
on m.AcNoId equals t.Id into tempTeacher
from ta in tempTeacher.DefaultIfEmpty()
select new
{
Type = m.TestOption.ToString(),
Student = st.StudentName ?? string.Empty,
Teacher = ta.TeacherName ?? string.Empty
}).ToList();
Instead of conditional join this query perform a following query on SQL Profiler
exec sp_executesql N'SELECT [m].[TestOption], COALESCE([s].[StudentName], #__Empty_0) AS [Student], COALESCE([t].[TeacherName], #__Empty_1) AS [Teacher]
FROM [Mapper] AS [m]
LEFT JOIN [Student] AS [s] ON [m].[AcNoId] = [s].[Id]
LEFT JOIN [Teacher] AS [t] ON [m].[AcNoId] = [t].[Id]
WHERE ([m].[TestOption] = 2) AND ([m].[TestOption] = 1)',N'#__Empty_0 nvarchar(4000),#__Empty_1 nvarchar(4000)',#__Empty_0=N'',#__Empty_1=N''
How can I do this????
You can use the below code, with no need to use join or where statements on _context.Mapper:
(from m in _context.Mapper
select new
{
Type = m.TestOption.ToString(),
Student = _context.Student
.FirstOrDefault(s =>
m.TestOption == TestOption.Student &&
s.Id == m.AcNoId) ?? string.Empty,
Teacher = _context.Teacher
.FirstOrDefault(t =>
m.TestOption == TestOption.Teacher &&
t.Id == m.AcNoId) ?? string.Empty,
})
.ToList();

Compare two arrays in LINQ query

I want to write LINQ query to compare two arrays. I want the query to be translated to the following query:
SELECT id, name
FROM persons
WHERE '{"dance", "acting", "games"}' && (hobbies);
That condition work in that way:
'{"dance"}' && '{"dance", "acting", "games"}'; -- true
'{"dance","singins"}' && '{"dance", "acting", "games"}'; -- true
'{"singins"}' && '{"dance", "acting", "games"}'; -- false
I wrote this query:
List<string> arr = new List<string>(){ "dance", "acting", "games" };
var query = (from p in _context.Persons
where arr.Any(kw => p.hobbies.Contains(kw))
select new
{
id = p.id,
name = p.name
}).ToList();
The translated query is:
SELECT p."id" AS id, p."name" AS name
FROM dataBase."Persons" AS p
It can understand that the filter performs in the server. so the query brings all the data from DB and filtered on the server. This causes to performance problems and not pass Load-Testing.
I need a query that will not only do the job but will also be translated to the above query with '&&'.
Is there any way in LINQ to execute this query?
Thanks
If your database looks similar like I am predicting this could be a solution. Some more code though but I think this should be executed as a SQL IN statement:
List<string> arr = new List<string>(){ "dance", "acting", "games" };
var matches = from hobby_person in _context.Hobbies_Persons
join person in _context.Persons on person.Id equals hobby_person.PersonId
join hobby in _context.Hobbies on hobby.Id equals hobby_person.HobbyId
where arr.Contains(hobby.Name)
select new
{
id = p.id,
name = p.name
}).ToList();

when inner join in linq how can i select same column without using model class

Actually ,I want to extract generic data from EF table without using models but unfortunately two columns with same name from different database crashed...
Here is the query
var query = (from jbct in entities.Table1.AsEnumerable()
join p in entities.Table2.AsEnumerable() on jbct.perid equals p.id
select new
{
jbct.id,
p.id
}).ToList();
try use a dynamic name
var query = (from jbct in entities.Table1.AsEnumerable()
join p in entities.Table2.AsEnumerable() on jbct.perid equals p.id
select new
{
Id1 = jbct.id,
Id2 = p.id
}).ToList();
Now I've found now my solution to usie dictionary class
Dictionary with object as value
var query = (from jbct in entities.Table1.AsEnumerable() join p in entities.Table2.AsEnumerable() on jbct.perid equals p.id select new Dictionary<String, Object>
{
{"jbct_id", jbct.id},
{"p_id", p.id}}
).ToList();
Thanks

ef core select records from tableA with matching fields in tableB

I'm trying to translate a query from raw sql to linq statement in EF Core 2
Query is something like this
SELECT * FROM TableA
WHERE FieldA = ConditionA
AND FieldB IN (SELECT FieldC FROM TableB WHERE FieldD = ConditionB)
FieldA and FieldB are from TableA, FieldC and FieldD are from TableB
I need all fields from TableA and none from TableB returned, so it should be something like
return Context.TableA
.Where(x => x.FieldA == ConditionA)
.[ some code here ]
.ToList()
my current solution is to get two distinct result sets and join them in code, something like this
var listA = Context.TableA
.Where(x => x.FieldA == ConditionA).ToList();
var listB = Context.TableB
.Where(x => x.FieldD == ConditionB).Select(x => x.FieldC).ToList();
listA.RemoveAll(x => !listB.Contains(x.FieldB);
return listA;
i hope it works, i still have to run tests on it, but i'm looking for a better solution (if anything exists)
You can simply use Contains function in query like this :
var ids = Context.TableB
.Where(p => p.FieldD == conditionD)
.Select(p => p.FieldC);
var result = Context.TableA
.Where(p => ids.Contains(p.FieldB))
.ToList();
It's a simple join that needs to be applied -
var result = (from a in Context.TableA.Where(x => x.FieldA == ConditionA )
join b in Context.TableB.Where(x => x.FieldD == ConditionB) on a.FieldB equals b.FieldC
select new {a}
).ToList();