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();
I'm trying to get a list in a linq with joins and get all events for specific user.
This is the query I have so far:
var runnerObject = from r in _context.Runners
join re in _context.RunnerEvents
on r.RunnerId equals re.RunnerId
join e in _context.Events
on re.EventId equals e.EventId
where r.RunnerId == runnerId
select new RunnerVM
{
RunnerId = r.RunnerId,
FirstName = r.FirstName,
LastName = r.LastName,
UserId = r.UserId,
Events = //get all events in Events table for the runnerId
};
Events should be all entries from Events table for that runner, based on their id which is joined in the RunnerEvents table. How can I get that?
Something like this?
var runnerObject = from r in _context.Runners
join re in _context.RunnerEvents
on r.RunnerId equals re.RunnerId
join e in _context.Events
on re.EventId equals e.EventId
where r.RunnerId == runnerId
select new RunnerVM
{
RunnerId = r.RunnerId,
FirstName = r.FirstName,
LastName = r.LastName,
UserId = r.UserId,
Events = r.Events.Select(e => new Event { }).ToList()
};
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
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
)
Problem: I would like to generate the exact sql below in the desired output using linq syntax (Entity framework 7)
The goal of the question is to generate the exact sql below!
Desired Output
select a.AppUserId, u.Email, a.FirstName, a.MiddleName, a.LastName, a.IsInternal, a.AspNetUserId, a.PictureLink, a.SignatureLink, a.PhoneNumber, a.Extension, a.FaxNumber, a.MobileNumber, a.Skype, r.Name as 'Role', a.SupervisorId, a.BackUpId, a.HasAutoAssignClaims, a.IsActive
from AppUser a
join AspNetUsers u on a.AspNetUserId = u.Id
left join AspNetUserRoles ur on u.Id = ur.UserId
left join AspNetRoles r on ur.RoleId = r.Id
I have only being able to get the exact same sql but with inner joins. I can't seem to get the two left joins. The code below here how I was able to generate the inner joins and also a fail attempt at generating the left joins.
SELECT [a].[AppUserId], [a].[FirstName], [a].[MiddleName], [a].[LastName], [a].[IsInternal], [a].[AspNetUserId], [a].[PictureLink], [a].[SignatureLink], [a].[PhoneNumber], [a].[Extension], [a].[FaxNumber], [a].[MobileNumber], [a].[Skype], [a].[SupervisorId], [a].[BackUpId], [a].[HasAutoAssignClaims], [a].[IsActive]
FROM [AppUser] AS [a]
INNER JOIN [AspNetUsers] AS [b] ON [a].[AspNetUserId] = [b].[Id]
INNER JOIN [AspNetUserRoles] AS [c] ON [b].[Id] = [c].[UserId]
INNER JOIN [AspNetRoles] AS [d] ON [a].[RoleId] = [d].[Id]
Code with inner join works but I want left joins....:
var query = (
//INNER JOIN
from a in _dbCtx.AppUser
join b in _dbCtx.Users
on a.AspNetUserId equals b.Id
////LEFT JOIN
join c in _dbCtx.UserRoles
on b.Id equals c.UserId
// // //LEFT JOIN (if you wanted right join the easiest way is to flip the order of the tables.
join d in _dbCtx.Roles
on a.RoleId equals d.Id
select new
{
AppUserId = a.AppUserId,
//Email = b.Email,
FirstName = a.FirstName,
MiddleName = a.MiddleName,
LastName = a.LastName,
IsInternal = a.IsInternal,
AspNetUserId = a.AspNetUserId,
PictureLink = a.PictureLink,
SignatureLink = a.SignatureLink,
PhoneNumber = a.PhoneNumber,
Extension = a.Extension,
FaxNumber = a.FaxNumber,
MobileNumber = a.MobileNumber,
Skype = a.Skype,
//Role = d.Name != null ? string.Empty :d.Name ,
SupervisorId = a.SupervisorId,
BackUpId = a.BackUpId,
HasAutoAssignClaims = a.HasAutoAssignClaims,
IsActive = a.IsActive
}).ToList();
Code with Left Join...which I am missing some concept doesnt work
what doesnt work is that on g2.RoleId equals d.Id into group3 line the g2 is not available. So how would I make c.RoleId available for my next left join? Basically after you group something you can no longer use it apparently.
var LeftJoin= (
//INNER JOIN
from a in _dbCtx.AppUser
join b in _dbCtx.Users
on a.AspNetUserId equals b.Id
////LEFT JOIN
join c in _dbCtx.UserRoles
on b.Id equals c.UserId into group2
from g2 in group2.DefaultIfEmpty() //makes it left join
join d in _dbCtx.Roles
on g2.RoleId equals d.Id into group3
from g3 in group3.DefaultIfEmpty()
select new
{
AppUserId = a.AppUserId,
Email = b.Email,
FirstName = a.FirstName,
MiddleName = a.MiddleName,
LastName = a.LastName,
IsInternal = a.IsInternal,
AspNetUserId = a.AspNetUserId,
PictureLink = a.PictureLink,
SignatureLink = a.SignatureLink,
PhoneNumber = a.PhoneNumber,
Extension = a.Extension,
FaxNumber = a.FaxNumber,
MobileNumber = a.MobileNumber,
Skype = a.Skype,
Role = g3.Name != null ? string.Empty :g3.Name ,
SupervisorId = a.SupervisorId,
BackUpId = a.BackUpId,
HasAutoAssignClaims = a.HasAutoAssignClaims,
IsActive = a.IsActive
}).ToList();
In case anyone comes to this question, thinking it hasn't been answered, the answer is currently buried in a comment chain after the question. I'm merely paraphrasing the key comments here.
The problem is that Entity Framework 7 is currently a release candidate and has some bugs. One of these bugs (Left Join doesn't work if the filter is composed on top) is causing the failure of the left join noted by the OP.
The solution, for now, is to revert to Entity Framework 6, or temporarily use a stored procedure or inline SQL until the bug is fixed.
If i understood you properly you problem is that EF is not generating LEft join. If yes then solution is pretty simple your Entities should have nullable property for instance
public class SomeClass
{
public int Id { get; set; }
public int? CategoryId { get; set; }
public Category Category {get;set:}
}
One option which is in my head
_dbCtx.SqlQuery<T>(SqlStringHEre).ToList()
Other option, and aspnet tables i would do it differently
var query = _dbCtx.AppUser
.Include(apu=>apu.AspNetUser)
.Include(apu=>apu.AspNetUser.Roles)
.Include(apu=>apu.AspNetUser.Roles.Select(r=>r.Role))
.ToList();
but here is problem as we talk in comments that IdentityUserRole does not have refference to role so lets fix that.
create class
public class UserToRole : IdentityUserRole<int>
{
public Role Role { get; set; }
}
Then extend your user class
public class YourUser : IdentityUser<int, IdentityUserLogin<int>, UserToRole, IdentityUserClaim<int>>
Now you can do what you want
_db.Users.Select(u=>u.Roles.Select(r=>r.Role.Name))
This is a work around that generates the data with a very bad query. It generate a series of calls to the database that does yield the same result set. However, it is definitely not the best query for the job. I am still waiting for RC2 and I will update the answer.
var query = (
//INNER JOIN
from a in _dbCtx.AppUser
join b in _dbCtx.Users
on a.AspNetUserId equals b.Id
from c in _dbCtx.UserRoles
.Where(x => b!=null && x.UserId == b.Id)
.DefaultIfEmpty()
from d in _dbCtx.Roles
.Where(x => a !=null && x.Id == a.RoleId)
.DefaultIfEmpty()
select new
{
AppUserId = a.AppUserId,
Email = b.Email,
FirstName = a.FirstName,
MiddleName = a.MiddleName,
LastName = a.LastName,
IsInternal = a.IsInternal,
AspNetUserId = a.AspNetUserId,
PictureLink = a.PictureLink,
SignatureLink = a.SignatureLink,
PhoneNumber = a.PhoneNumber,
Extension = a.Extension,
FaxNumber = a.FaxNumber,
MobileNumber = a.MobileNumber,
Skype = a.Skype,
Role = d.Name != null ? string.Empty :d.Name ,
SupervisorId = a.SupervisorId,
BackUpId = a.BackUpId,
HasAutoAssignClaims = a.HasAutoAssignClaims,
IsActive = a.IsActive
}).ToList();