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();
Related
I am tried to use .FromSqlRaw and .FromSqlInterpolated in ASP.NET Core 3.1, EntityFramework Core 3.1, DotVVM, SQL Server.
var result = SomeDbContext
.SomeModels
.FromSqlRaw("Select [column1], [column2] From [schema].[ufnTableValueFunction] (#FirstParam, #SecondParam, #ThirdParam)",
parameters: new[] { firstParam, secondParam, thirdParam })
.AsNoTracking()
.ToListAsync();
var result = SomeDbContext
.SomeModels
.FromSqlInterpolated($"select * from [schema].[ufnTableValueFunction] ({firstParam},{secondParam},{thirdParam})")
.AsNoTracking()
.ToListAsync();
When I use SQL Server Profiler, I find this generated SQL from application and I try use it in database, it is returned data to me. In application no data returned into result. In second application with same system of selecting data with table-valued function all is working fine. What I must do for successful selecting data?
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 am running executing raw sql to delete some records that I added for the test. If I run the same query in management studio it works fine but when I run that query EF Core 2.0 it throws below error
System.Data.SqlClient.SqlException: 'Conversion failed when converting the nvarchar value '1,2' to data type int.'
Code
var idList = await Context.User.ToListAsync();
var ids = string.Join(",",idList.Select(x=>x.Id));
await _context.Database.ExecuteSqlCommandAsync($"Delete from User where Id in ({ids}) and RoleId = {contact.RoleId}");
Query executing
Delete from sale.WatchList where OfferId in (1,2) and UserId = 9
Could anybody please advise on what wrong with the above code.
Thanks
EF Core will transform interpolated strings into queries with parameters to create reusable queries and protect against SQL Injection vulnerabilities. See: Raw SQL Queries - EF Core - Passing Parameters
So
$"Delete from User where Id in ({ids}) and RoleId = {contact.RoleId}"
is transformed into
Delete from User where Id in (#ids) and RoleId = #RoleId
With SqlParameters bound.
If that's not what you want, just build the SQL Query on a previous line.
This will not work. You have to write dynamic query. Please try like below one
var idList = await _dataContext.User.ToListAsync();
var ids = string.Join(",", idList.Select(x => x.Id));
await _dataContext.Database.ExecuteSqlCommandAsync($"execute('Delete from User where Id in ({ids}) and RoleId = {contact.RoleId}')");
although accepted answer does work, it creates lot of warnings so for now I am using what #Abu Zafor suggested with small change/fix
await _dataContext.Database.ExecuteSqlCommandAsync($"execute('Delete from User where Id in ({ids}) and RoleId = {contact.RoleId}')",ids,contact.RoleId);
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 currently have an issue in that there are thousands of plans created on the DB for 1 style of EF query.
The query itself is parametrized, but the parameter name keeps changing and hence the text is different, and so results in a fresh new compile for each query hitting my DB server.
So the query looks like this.
(#p__linq__100687 int)SELECT [Extent1].[MyColumn] From MyTable [Extent1]
Where Column1 = #p__linq__100687
and the next one looks like this
(#p__linq__100688 int)SELECT [Extent1].[MyColumn] From MyTable [Extent1]
Where Column1 = #p__linq__100688
What I would like EF to do is
(#p__linq__1 int)SELECT [Extent1].[MyColumn] From MyTable [Extent1]
Where Column1 = #p__linq__1
And then keep reusing the query above instead of incrementing and then being
forced to create a new plan.
So when I trawl through the plan cache on the DB I get a total of 7GB of plans which have only been used once.
I am a DBA and need to figure out what to tell the Vendor Devs since they are adamant that this is the correct way to implement EF as per MS.
I have searched google and asked a couple of dev friends around the construction of the code in the background but the answer still eludes.
I just did some tests using VS 2017 and EF 6 and had no problem with this, even trying some bad c# codes.
I tried this:
AdventureWorks2016Entities ctx = new AdventureWorks2016Entities();
for (var i = 1; i <= 50; i++)
{
var query = (from x in ctx.bigProduct.AsNoTracking()
where x.ReorderPoint == i
select x);
var result = query.ToList();
}
and this :
for (var i = 1; i <= 50; i++)
{
AdventureWorks2016Entities ctx = new AdventureWorks2016Entities();
var query = (from x in ctx.bigProduct.AsNoTracking()
where x.ReorderPoint == i
select x);
var result = query.ToList();
}
The first code block is re-creating the query in each iteration and the 2nd code block is also re-creating the context in each iteration. None of these options created the plan cache bloat you are suffering.
What's the EF version your application is using ?
However, I found this problem with the decimal type in EF. I just posted a question about this, you can find it here - How to avoid plan cache bloat using queries in entity framework