Can we write an aggregate function for my SQL script.? As I expect that I can make a function as string_agg of SQL Server.
Select e.EmployeeId, MyAggregateFunction(e.Task, ', ')
From EmployeeTask as e
Group by e.EmployeeId
I know I can use string_agg. But I want to write it myself to use it in entity framework. Entity Framework cannot translate into string_agg.
This is my code in Entity Framework:
var result = _context.EmployeeTask.FindAsQueryable().GroupBy(x => x.EmployeeId).Select(x => new {EmployeeId = x.Key, Tasks = DbFunction.MyAggregateFunction(x => x.Task)});
I don't want to use .AsEnumrable() before GroupBy().
Related
I need to able to translate my sql query to EF code, my sql query is using one where statement of IN operator and not sure how to also do that in EF.
I have tried doing a EF code the follwing code below but is not working.
private ManufacturingDbContext _manufacturingDbContext;
public List<string> GetManufacturerOrders()
{
var context = _manufacturingDbContext;
var ids = new[] {1, 2};
var manufacturingOrderList = context.ManufacturingOrders.Where(s => s.statusId == ids.Contains(s.statusId)).Select(o => o.lookupCode).ToList();
return manufacturingOrderList;
}
Here is the sql query where I need it translated to EF Code
select
o.lookupCode
from dbo.ManufacturingOrders o
where o.statusId in(1, 2)
the end result of this is to just get the lookupcode as you can see in my sql query, and that will display in my app. I looked other sites in google and also here and I could not find an exact answer of my question.
Should be something like:
var manufacturingOrderList = context.ManufacturingOrders
.Where(s => ids.Contains(s.statusId))
.Select(o => o.lookupCode)
.ToList();
I'm trying to achieve a query similar to this:
SELECT r.*, (SELECT COUNT(UserID) FROM RoleUsers ru WHERE ru.RoleId = r.Id) AS Assignments
FROM Roles r
To retrieve the number of the users per each role.
The simplest and the most straightforward option to implement desired output:
this.DbContext.Set<Role>().Include(x => x.RoleUser)
.Select(x => new { x, Assignments = x.RoleUsers.Count() });
Retrieves all the roles, and then N queries to retrieve count:
SELECT COUNT(*)
FROM [dbo].[RoleUsers] AS [r0]
WHERE #_outer_Id = [r0].[RoleId]
Which is not an option at all. I tried also to use GroupJoin, but it loads all the required data set in one query and performs grouping in memory:
this.DbContext.Set<Role>().GroupJoin(this.DbContext.Set<RoleUser>(), role => role.Id,
roleUser => roleUser.RoleId, (role, roleUser) => new
{
Role = role,
Assignments = roleUser.Count()
});
Generated query:
SELECT [role].[Id], [role].[CustomerId], [role].[CreateDate], [role].[Description], [role].[Mask], [role].[ModifyDate], [role].[Name], [assignment].[UserId], [assignment].[CustomerId], [assignment].[RoleId]
FROM [dbo].[Roles] AS [role]
LEFT JOIN [dbo].[RoleUser] AS [assignment] ON [role].[Id] = [assignment].[RoleId]
ORDER BY [role].[Id]
Also, I was looking into a way, to use windowing functions, where I can just split count by partition and use distinct roles, but I have no idea how to wire up windowing function in EF:
SELECT DISTINCT r.*, COUNT(ra.UserID) OVER(PARTITION BY ru.RoleId)
FROM RoleUsers ru
RIGHT JOIN Roles r ON r.Id = ru.RoleId
So, is there any way to avoid EntitySQL?
Currently there is a defect in EF Core query aggregate translation to SQL when the query projection contains a whole entity, like
.Select(role => new { Role = role, ...}
The only workaround I'm aware of is to project to new entity (at least this is supported by EF Core) like
var query = this.DbContext.Set<Role>()
.Select(role => new
{
Role = new Role { Id = role.Id, Name = role.Name, /* all other Role properies */ },
Assignments = role.RoleUsers.Count()
});
This translates to single SQL query. The drawback is that you have to manually project all entity properties.
this.DbContext.Set<Role>()
.Select(x => new { x, Assignments = x.RoleUsers.Count() });
you dont need to add include for RoleUser since you are using Select statement. Furhtermore, I guess that you are using LazyLoading where this is expected behavior. If you use eager loading the result of your LINQ will run in one query.
you can use context.Configuration.LazyLoadingEnabled = false; before your LINQ query to disable lazy loading specifically for this operation
I have an SQL query.
SELECT
nguyenlieu.manguyenlieu,
nguyenlieu.tennguyenlieu,
SUM(chitietnhapmua.soluong) AS slsum
FROM chitietnhapmua
JOIN nguyenlieu
ON nguyenlieu.manguyenlieu = chitietnhapmua.manguyenlieu
JOIN
(SELECT nhapmua.* FROM nhapmua WHERE nhapmua.trangthai = 1) AS nhapmua
ON nhapmua.maphieunhap = chitietnhapmua.maphieunhap
GROUP BY nguyenlieu.manguyenlieu
It run on the SQL. I have to try
$data = DB::table('nguyenlieu')
->join('chitietnhapmua','nguyenlieu.manguyenlieu','=','chitietnhapmua.manguyenlieu')
->join('nhapmua',function($join){
$join->on('nhapmua.maphieu','=','chitietnhapmua.maphieu')
->where('nhapmua.trangthai','=','1');
})
->select('nhapmua.maphieunhap','nguyenlieu.manguyenlieu','nguyenlieu.tennguyenlieu','chitietnhapmua.soluong')
->get();
but I can't to translate to Laravel framework using class DB.
I need a very simple query in my aplication but I can't figure out how to translate it into Linq-to-SQL because I need it in an asp.net application.
It is neccesery that it is a lambda expression because of internal procedures.
In T-SQL it looks like this:
select top 1 [datum]
from Test
where Datum <> (select max (Datum) from Test)
Sorry for the stupid question in advance.
You can use the Max function inline with the query
var result = Test
.Where(t => t.Datum != Test.Max(t1 => t1.Datum))
.Select(t => t.Datum)
.FirstOrDefault();
To apply such query using lambda expression first you need to fetch all records from table test and the list that you get can be used to get the output you want.
Sample query would be as follows after you fetch the list from the database.
var test= Tests
.OrderByDescending(e => e.datum)
.Skip(1)
.First();
I need to convert this SQL Query to LINQ Query, also I need to expose the SQL Select properties:
SELECT Problem.ProblemID, ProblemFactory.ObjectiveID, Objective.Name, ProblemFactory.Time, ProblemType.ProblemTypeName, ProblemFactory.OperationID,
ProblemFactory.Range1ID, ProblemFactory.Range2ID, ProblemFactory.Range3ID, ProblemFactory.Range4ID,
ProblemFactory.MissingNumber
FROM Problem INNER JOIN ProblemFactory ON Problem.ProblemFactoryID = ProblemFactory.ProblemFactoryID
INNER JOIN ProblemType ON ProblemFactory.ProblemTypeID = ProblemType.ProblemTypeID
INNER JOIN Objective ON Objective.ObjectiveID = ProblemFactory.ObjectiveID
UPDATE 1:
This is what I have:
var query = from problem in dc.Problem2s
from factory
in dc.ProblemFactories
.Where(v => v.ProblemFactoryID == problem.ProblemFactoryID)
.DefaultIfEmpty()
from ...
And I'm using this example: What is the syntax for an inner join in LINQ to SQL?
Something like this?
var query =
from p in ctx.Problem
join pf in ctx.ProblemFactory on p.ProblemFactoryID equals pf.ProblemFactoryID
join pt in ctx.ProblemType on pf.ProblemTypeID equals pt.ProblemTypeID
join o in ctx.Objective on pf.ObjectiveID equals o.ObjectiveID
select new
{
p.ProblemID,
pf.ObjectiveID,
o.Name,
pf.Time,
pt.ProblemTypeName,
pf.OperationID,
pf.Range1ID,
pf.Range2ID,
pf.Range3ID,
pf.Range4ID,
pf.MissingNumber,
};
But what do you mean by the "SQL Select properties"?
One of the benefits of an ORM like Linq-to-SQL is that we don't have to flatten our data to retrieve it from the database. If you map your objects in the designer (i.e. if you have their relationships mapped), you should be able to retrieve just the Problems and then get their associated properties as required...
var problems = from problem in dc.Problem2s select problem;
foreach (var problem in problems)
{
// you can work with the problem, its objective, and its problem type.
problem.DoThings();
var objective = problem.Objective;
var type = problem.ProblemType;
}
Thus you retain a logical data structure in your data layer, rather than anonymous types that can't easily be passed around.