SQL query to linq (with/as, update) - sql

I have difficulties and struggle in changing SQL query to linq.
Here is one of my example code:
string sql = "WITH cte as
(SELECT TOP(1) PART_ID
FROM [History]
WHERE PART_ID = '' AND CURRENT_WEIGHT is NULL)
UPDATE cte
SET PART_ID = #PART_ID";
Here what I have done for a part:
db.Histories
.Select(u => new
{
u.PartId,
u.CurrentWeight
})
.Where(u => u.PartId == "")
.Where(u => u.CurrentWeight == null)
.Take(1);
I have no idea to change the with cte as, update statement. Hope to receive some helps. Thank you.

use this code
var history = db.Histories
.Where(u => u.PartId == "" && u.CurrentWeight == null).Take(1)
.FirstOrDefault();
history.PartId = newValue;
db.SaveChanges();

Related

Database rankings positions. Performance problem

I am having a performance issue retrieving three game rankings. The code below runs approximately 300 ms and it's to long for my manager.
public async Task<PointsDto> UserPoints(int userId, int countryId)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
var userData = await context.UsersProfile
.AsNoTracking()
.Select(x => new { x.SeasonPoints, x.RankingPoints, x.Id })
.FirstOrDefaultAsync(x => x.Id == userId);
var seasonPlace = await context.UsersProfile
.Select(x => x.SeasonPoints)
.Where(x => x > userData.SeasonPoints)
.CountAsync();
var regionPlace = await context.Users
.Include(x => x.UserProfile)
.Select(x => new { x.UserProfile.RankingPoints, x.CountryId })
.Where(x => x.CountryId == countryId && x.RankingPoints > userData.RankingPoints)
.CountAsync();
var worldPlace = await context.UsersProfile
.Select(x => x.RankingPoints)
.Where(x => x > userData.RankingPoints)
.CountAsync();
var result = new PointsDto()
{
RankingPoints = userData.RankingPoints,
SeasonPoints = userData.SeasonPoints,
RegionPlace = regionPlace + 1,
SeasonPlace = seasonPlace + 1,
WorldPlace = worldPlace + 1
};
stopwatch.Stop();
Console.WriteLine(stopwatch.ElapsedMilliseconds);
return result;
}
I tried to download all users and count them. Then it worked better, but I'm afraid when there will be 1,000,000 users and at least 1/10 will download so much data, it will be a heavy burden on the memory. It would be good to cut the execution time by at least half, but I don't know how to do it anymore.
For a performance reason I would delegate it to a Sql Server TVF. Kind of
create function Ranking(#userId int, #countryId int)
returns table
as
return
with userdata as (
select SeasonPoints, RankingPoints
from UsersProfile
where Id = #userId
)
select count(case when x.SeasonPoints > userData.SeasonPoints then x.Id end) seasonPlace,
count(case when x.CountryId = #countryId and x.RankingPoints > userData.RankingPoints then x.Id end) regionPlace,
count(case when x.RankingPoints > userData.RankingPoints then x.Id end) worldPlace,
from UsersProfile x
join userData on (x.RankingPoints > userData.RankingPoints
or x.SeasonPoints > userData.SeasonPoints);
The query optimizer would advice proper indexes if missing.

Entity Framework Linq to SQL expression containing LEFT JOIN

I'm attempting to translate some T-SQL to an Entity Framework Core lambda expression. It involves an inner join and a left joing with a where clause.
Here is the working SQL query:
SELECT
AspNetUsers.*, Exclusions.*
FROM
AspNetUsers
JOIN Exclusions ON
AspNetUsers.FirstName = Exclusions.FirstName
AND AspNetUsers.LastName = Exclusions.LastName
LEFT JOIN ExclusionsMatches ON
ExclusionsMatches.RowHash = Exclusions.RowHash
WHERE
ExclusionsMatches.MatchIgnoredByUserId IS NULL
Which I have thus far translated into LINQ lambda as such:
var result = _db.Users
.Join(_db.Exclusions, usr => new { usr.FirstName, usr.LastName }, Exc => new { Exc.FirstName, Exc.LastName }, (usr, Exc) => new { usr, Exc })
.GroupJoin(_db.ExclusionsMatches, i => i.Exc.RowHash, x => x.RowHash, (i, ExcMatch) => new { User = i.usr, Exc = i.Exc, ExcMatch = ExcMatch })
.SelectMany(temp => temp.ExcMatch.DefaultIfEmpty(), (temp, p) => new { User = temp.User, Exc = temp.Exc, ExcMatch = temp.ExcMatch})
This seems to give me the desired query output, but I can't seem to figure out how to get the WHERE ExclusionsMatches.MatchIgnoredByUserId IS NULL clause translated.
Any thoughts on how the WHERE might be achieved? I'm also open to changing from lambda expression to linq query expression.
Thanks!
I believe using LINQ is more readable so I can provide an answer using LINQ as below.
from user in _db.Users
join excl in _db.Exclusions on new { usr.FirstName , usr.LastName} equals {excl.FirstName , excl.LastName}
join exclMtch in _db.ExclusionsMatches on excl.RowHash equals exclMtch.RowHash into grp
from itm in grp.DefaultIfEmpty()
where itm.MatchIgnoredByUserId == null
select new {
user,
excl
}
Otherwise, if you insist on using Lambda, first you have to select the field in your final selects and then add the needed where in the end of query.
var result = _db.Users
.Join(_db.Exclusions, usr => new { usr.FirstName, usr.LastName }, Exc => new { Exc.FirstName, Exc.LastName }, (usr, Exc) => new { usr, Exc })
.GroupJoin(_db.ExclusionsMatches, i => i.Exc.RowHash, x => x.RowHash, (i, ExcMatch) => new { User = i.usr, Exc = i.Exc, ExcMatch = ExcMatch MatchIgnoredByUserId = i.MatchIgnoredByUserId })
.SelectMany(temp => temp.ExcMatch.DefaultIfEmpty(), (temp, p) => new { User = temp.User, Exc = temp.Exc, ExcMatch = temp.ExcMatch, MatchIgnoredByUserId= temp.MatchIgnoredByUserId })
.Where(q => q.MatchIgnoredByUserId == null )
Do not forget to track your query in SQL Profiler :)

Complex DateTime query in Entity Framework

I would like to ask how to write a complex DateTime query in Entity Framework as below:
I have this code in service:
Func<DateTime, DateTime> calculate24HoursLater = (date) =>
{
if (date.DayOfWeek == DayOfWeek.Friday)
return date.AddDays(3);
if (date.DayOfWeek == DayOfWeek.Saturday)
return date.AddDays(3).Date;
if (date.DayOfWeek == DayOfWeek.Sunday)
return date.AddDays(2).Date;
return date.AddDays(1);
};
var unactionedEnquiries =
dataContext.ContactedBrokerEnquiries
.Include("ContactedBrokers")
.Where(
x => x.ContactedBrokers.All(c => c.Status == (byte)LeadStatus.Rejected) ||
x.ContactedBrokers.Any(c => c.Status == (byte)LeadStatus.New && calculate24HoursLater(c.CreatedDate) < DateTime.Now)
).OrderByDescending(c => c.CreatedDate);
The result unactionedEnquiries, I expect it should be IQueryable. It means SQL server does not execute until my next statement
However, I get exception on calculate24HoursLater(c.CreatedDate) < DateTime.Now)
This statment cannot translate into SQL statement. I know the reason but I dont know how to write that rule in Entity Framework query
Important: I dont prefer to push all of data into RAM then filter with that condition. Ideally, it should be in SQL-Server
Could you please let me know how to write them in SQL-EF statement?
You may want to take a look at possibly using the SQLFunctions Methods that are available for doing date operations in LINQ queries
Sample (Untested) Try replacing your Func definition with the following:
Func<DateTime, DateTime> calculate24HoursLater = (date) =>
{
if (date.DayOfWeek == DayOfWeek.Friday)
return SqlFunctions.DateAdd("day", 3, date).Value;
if (date.DayOfWeek == DayOfWeek.Saturday)
return SqlFunctions.DateAdd("day", 3, date).Value;
if (date.DayOfWeek == DayOfWeek.Sunday)
return SqlFunctions.DateAdd("day", 2, date).Value;
return SqlFunctions.DateAdd("day", 1, date).Value;
};
As I saw here #andrew's genius answer, you can do:
var calcDate = DateTime.Now.AddHours(-24);
var unactionedEnquiries =
dataContext.ContactedBrokerEnquiries
.Include("ContactedBrokers")
.Where(
x => x.ContactedBrokers.All(c => c.Status == (byte)LeadStatus.Rejected) ||
x.ContactedBrokers.Any(c => c.Status == (byte)LeadStatus.New && c.CreatedDate < calcDate)
).OrderByDescending(c => c.CreatedDate);

translating sql statement to linq

I have a working sql statement and want it as linq statement or linq methode chain.
My statement is:
SELECT T1.*
FROM (SELECT Col1, MAX(InsertDate) as Data
FROM Zugbewegungsdaten
GROUP BY Loknummer) as temp JOIN T1
ON (T1.Col1= temp.Col1
AND Zugbewegungsdaten.InsertDate= temp.Date)
WHERE Col3=1
ORDER BY Loknummer
Can anybody help me to translate it?
Edit after comment:
Ok, my result for the inner select:
var maxResult = (from data in context.T1
group data by data.Col1
into groups
select new
{
Train = groups.Key,
InsertDate= groups.Max( arg => arg.InsertDate)
}) ;
I tried the join like this:
var joinedResult = from data in context.T1
join gdata in maxResult on new
{
data.Col1,
data.InsertDate
}
equals new
{
gdata.Col1,
gdata.InsertDate
}
select data;
But i get a compiler error by the join that the typeargument are invalid.
In the case that the join works i whould use a where to filter the joinedResult.
var result = from data in joinedResult
where data.Col3 == true
select data;
After much more "try and error", I got this version it looks like it works.
var joinedResult = ( ( from data in context.T1
group data by data.Col1
into g
select new
{
Key= g.Key,
Date = g.Max( p => p.InsertDate)
} ) ).Join( context.T1,
temp => new
{
Key = temp.Key,
InsertDate = temp.Date
},
data => new
{
Key = data.Col1,
InsertDate = data.InsertDate
},
( temp,
data ) => new
{
temp,
data
} )
.Where( arg => arg.data.Col3)
.OrderBy( arg => arg.data.Col1)
.Select( arg => arg.data );
Could it be that i have to set the same property names (Key, InsertDate) by joins over multi columns?

Convert SQL query to Nhibernate Criteria

My SQL query:
select [CompanyId]
from dbo.Bussiness_Company
where [BussinessId] in (11,12,13)
group by [CompanyId]
having COUNT(distinct [BussinessId])=3
Explain:
I have a table Bussiness_Company table :
Bussiness_Company
Id*
BussinessId
CompanyId
My data:
Id---------BussinessId------------CompanyId
1----------10---------------------100
2----------11---------------------100
3----------12---------------------100
Resaul query
CompanyId
100
Thank for any hepl!
Sloved:
This is my code:
DetachedCriteria detachedCriteria = DetachedCriteria.For<BussinessCompany>();
detachedCriteria.SetProjection(Projections.Property("Company"));
detachedCriteria.SetProjection(Projections.GroupProperty("Company"));
Disjunction disjunction = Restrictions.Disjunction();
foreach (Bussiness bussiness in list)
{
disjunction.Add(Restrictions.Eq("Bussiness", bussiness ));
} detachedCriteria.Add(disjunction).Add(Restrictions.Eq(Projections.CountDistinct<BussinessCompany>(m => m.Bussiness), list.Count));
IList<Sonomi.Core.BusinessObjects.Bussiness> bussiness =
bussinessUnitManager.CreateCriteria().Add(Subqueries.PropertyIn("Id", detachedCriteria)).List
<Sonomi.Core.BusinessObjects.BussinessUnit>();
dgrCer.DataSource = bussiness;
dgrCer.DataBind();
You can try a such QueryOver code:
var bussinessIdCount = 3;
var bussinessIds = new[] { 11, 12, 13 };
Bussiness_Company bussinessCompany = null;
session.QueryOver(() => bussinessCompany)
.WhereRestrictionOn(() => bussinessCompany.BussinessId).IsIn(bussinessIds)
.Select(Projections.Group(Projections.Property(() => bussinessCompany.CompanyId)))
.Where(Restrictions.Gt(Projections.CountDistinct(() => bussinessCompany.BussinessId), bussinessIdCount));