Complex SQL to LINQ conversion with subquery - sql

I am trying to convert this expression into LINQ from SQL, but a bit too difficult for me, maybe you can help me with this!
SELECT TOP (2) RecipeID, UserID, Name, Servings, PreparationTime, TotalTime, DifficultyLevelID, CuisineID, DishID, MainIngredientID, PriceLevelID, FlavourID, Instructions,
Notes, Thumbnail, VideoLink
FROM dbo.Recipes
WHERE (RecipeID NOT IN
(SELECT DISTINCT Recipes_1.RecipeID
FROM dbo.Allergies INNER JOIN
dbo.UsersAllergies ON dbo.Allergies.AllergyID = dbo.UsersAllergies.AllergyID INNER JOIN
dbo.IngredientsAllergies ON dbo.Allergies.AllergyID = dbo.IngredientsAllergies.AllergyID INNER JOIN
dbo.Ingredients ON dbo.IngredientsAllergies.IngredientID = dbo.Ingredients.IngredientID INNER JOIN
dbo.RecipesIngredients ON dbo.Ingredients.IngredientID = dbo.RecipesIngredients.IngredientID INNER JOIN
dbo.Recipes AS Recipes_1 ON dbo.RecipesIngredients.RecipeID = Recipes_1.RecipeID INNER JOIN
dbo.Users ON dbo.UsersAllergies.UserID = dbo.Users.UserID INNER JOIN
dbo.AllergyFactors ON dbo.IngredientsAllergies.AllergyFactorID = dbo.AllergyFactors.AllergyFactorID
WHERE (dbo.Users.UserID = 3) AND (dbo.AllergyFactors.AllergyFactorID < 3)))

It would be easier to help you if you showed us what you have already tried, but a Linq expression like this should give you the same result set
var query = (from rec in context.Recipes
where !(from al in context.Allergies
from ua in context.UsersAllergies.Where(x => al.AllergyID == x.AllergyID)
from ia in context.IngredientsAllergies.Where(x => al.AllergyID == x.AllergyID)
from in in context.Ingredients.Where(x => ia.IngredientID == x.IngredientID)
from ri in context.RecipesIngredients.Where(x => in.IngredientID == x.IngredientID)
from re in context.Recipes.Where(x => ri.RecipeID == x.RecipeID)
from us in context.Users.Where(x => ua.UserID == x.UserID)
from af in context.AllergyFactors.Where(x => ia.AllergyFactorID == x.AllergyFactorID)
where us.UserID == 3 && af.AllergyFactorID < 3
select re.RecipeID)
.Distinct()
.Contains(rec.RecipeID)
select new
{
rec.RecipeID,
rec.UserID,
rec.Name,
rec.Servings,
rec.PreparationTime,
rec.TotalTime,
rec.DifficultyLevelID,
rec.CuisineID,
rec.DishID,
rec.MainIngredientID,
rec.PriceLevelID,
rec.FlavourID,
rec.Instructions,
rec.Notes,
rec.Thumbnail,
rec.VideoLink
}).Take(2);

Related

where clause subquery in LINQ

I am trying to convert my SQL syntax to the LINQ query , And I have a problem with a subquery.
I want to select max date-time with an Id in a table as a subquery for another select command but I don't know what's right or wrong with this below code.
what I have in Sql
select ap.* ,aph.Lat as 'personLat',aph.Lng as 'personLng',l.cityId,l.Lat as 'LifecenterLat',l.lng as 'LifecenterLng',l.Id as 'LifeCenterId'
from Applicant ap
inner join ApplicantAddressHistory aph on ap.Id = aph.ApplicantId
inner join LifePlusCenter l on aph.CityId = l.CityId
Where ap.FamilyRoleTypeId = '82e26080-fda6-4396-946c-40d0e267f1f3' and aph.CreatedDate in (select max(CreatedDate) from ApplicantAddressHistory
where ApplicantAddressHistory.ApplicantId = ap.Id)
order by ap.NationalityCode
And what I have tried in linq
var innerJoinMultipleTables = from app in db.Applicant.Where(x => x.FamilyRoleTypeId == Guid.Parse("82e26080-fda6-4396-946c-40d0e267f1f3"))
join aph in db.ApplicantAddressHistory on app.Id equals aph.ApplicantId
where aph.CreatedDate == db.ApplicantAddressHistory.Max(x => x.CreatedDate && x.Id=aph.Id)
join l in db.LifePlusCenter on aph.CityId equals l.CityId
let centerLat = l.Lat
let centerLng = l.Lng
orderby app.NationalityCode
select new { app, aph.Lat, aph.Lng, l.CityId, l.Branch, centerLat, centerLng };
without this below line of code ,my linq works correctly.
where aph.CreatedDate == db.ApplicantAddressHistory.Max(x => x.CreatedDate && x.Id=aph.Id)
I need something like this below code in Linq as a subquery
select max(CreatedDate) from ApplicantAddressHistory where ApplicantAddressHistory.ApplicantId = '9836CEC4-EDCB-492C-9899-DF4279210CD2'
I finally tried this and it workd but dont know its correct way or not?!
var innerJoinMultipleTables = from app in db.Applicant.Where(x => x.FamilyRoleTypeId == Guid.Parse("82e26080-fda6-4396-946c-40d0e267f1f3"))
join aph in db.ApplicantAddressHistory on app.Id equals aph.ApplicantId
let rept_max = (from c in db.ApplicantAddressHistory
where c.Id == app.Id
select c.CreatedDate).Max()
where aph.CreatedDate == rept_max
join l in db.LifePlusCenter on aph.CityId equals l.CityId
let centerLat = l.Lat
let centerLng = l.Lng
orderby app.NationalityCode
select new { app, aph.Lat, aph.Lng, l.CityId, l.Branch, centerLat, centerLng };
Am not sure how it works in Linq, but you can modify your query like below to get latest details as per CreatedDate for each ApplicantId.
select ap.* ,aph.Lat as 'personLat',aph.Lng as 'personLng',l.cityId,l.Lat as 'LifecenterLat',l.lng as 'LifecenterLng',l.Id as 'LifeCenterId'
from Applicant ap
inner join
(select *
from
(select *,row_number() over(partition by ApplicantId order by CreatedDate desc) rw
from ApplicantAddressHistory
) p
where p.rw=1
) aph
on ap.Id = aph.ApplicantId
inner join LifePlusCenter l
on aph.CityId = l.CityId
Where ap.FamilyRoleTypeId = '82e26080-fda6-4396-946c-40d0e267f1f3'
/*
and aph.CreatedDate in (
select max(CreatedDate) from ApplicantAddressHistory
where ApplicantAddressHistory.ApplicantId = ap.Id
)
*/
order by ap.NationalityCode
Finally I came up to :
var z = from app in db.Applicant
join aph in db.ApplicantAddressHistory on app.Id equals aph.ApplicantId
join l in db.LifePlusCenter on aph.CityId equals l.CityId
let createDate = app.ApplicantAddressHistory.Max(c => c.CreatedDate)
where createDate.HasValue && aph.CreatedDate == createDate
&& app.FamilyRoleTypeId == Guid.Parse("82e26080-fda6-4396-946c-40d0e267f1f3")
let personLat = aph.Lat
let personLng = aph.Lng
let centerId = l.Id
let LifecenterLat = l.Lat
let LifecenterLng = l.Lng
orderby app.NationalityCode
select new { app, aph, l, app.Id, l.CityId, centerId, personLat, personLng, LifecenterLat, LifecenterLng };

how to convert left join SQL script to Linq script?

How can I convert left join to linq script. I have a T-SQL like this:
SELECT
es.StandardID,
COUNT(DISTINCT esc.StandardCourseID) AS CourseIDCount,
COUNT(DISTINCT esp.StandardPostID) AS PostIDCount
FROM EduStandards AS es
LEFT JOIN EduStandardCourses AS esc
ON es.StandardID = esc.StandardID
LEFT JOIN EduStandardPosts AS esp
ON es.StandardID = esp.StandardID
GROUP BY es.StandardID
That I want to convert this to linq.
Following is the query with left join that is replica of your query in linq.
var query = (from es in dbContext.EduStandards
join esc in dbContext.EduStandardCourses on es.StandardID equals esc.StandardID into ssc
from esc in ssc.DefaultIfEmpty()
join esp in dbContext.EduStandardPosts on es.StandardID equals esp.StandardID into ssp
from esp in ssp.DefaultIfEmpty()
select new { StandardId = es.StandardID, CourseCount = ssc.Count(), PostCount = ssp.Count() }).Distinct().ToList();
But I think we need not to apply left join in linq to calculate count. Following optimized linq query will return same result.
var query2 = (from es in dbContext.EduStandards
join esc in dbContext.EduStandardCourses on es.StandardID equals esc.StandardID into ssc
join esp in dbContext.EduStandardPosts on es.StandardID equals esp.StandardID into ssp
select new { StandardId = es.StandardID, CourseCount = ssc.Count(), PostCount = ssp.Count() });
This is what I've come up with
var query = from es in db.EduStandards
join esc1 in db.EduStandardCourses
on es.StandardId equals esc1.StandardId into esc
from c in esc.DefaultIfEmpty()
join esp1 in db.EduStandardPosts
on es.StandardId equals esp1.StandardId into esp
from p in esp.DefaultIfEmpty()
group new { es.StandardId, Course = c, Post = p } by es.StandardId into g
select new
{
StandardId = g.Key,
CourseIdCount = g.Where(x => x.Course != null).Count(),
PostIdCount = g.Where(x => x.Post != null).Count(),
};
However, I'm not entirely sure if it'll work for EF.
You could always do something like this:
var query = from es in db.EduStandards
select new
{
es.StandardId,
CourseIdCount = db.EduStandardCourses.Where(esc => esc.StandardId == es.StandardId).Distinct().Count(),
PostIdCount = db.EduStandardPosts.Where(esp => esp.StandardId == es.StandardId).Distinct().Count()
};
Also, I can't attest to the performance of either one of these queries due to the lack of knowledge of your database.

Linq To entity no full join issue

I have the following SQL script that gives me the results i'm after , i'm having trouble replicating the full join and the count distinct on the activities count:
select ActivityCount,ActivityComplete, ImagePath, SubjectTitle from
(select
Count(Distinct(Act.[ActivityID])) as ActivityCount,
Sum(Case when (([OutcomeID] = 1 or [OutcomeID] = 3) and AOU.ActivityUserID=1 ) Then 1 Else 0 End) As ActivityComplete,
Sub.[SubjectImageName] as ImagePath,
Sub.SubjectTitle as SubjectTitle
from [dbo].[UserActivityOutcome] AOU
full join Activity Act on Act.[ActivityID] = AOU.[ActivityID]
left join Category Cat on Act.[CategoryID] = Cat.[CategoryID]
left join Subject Sub on Cat.[SubjectID] = Sub.[SubjectID]
group by Sub.SubjectTitle, Sub.[SubjectImageName]
) as x
results:
</head>
<body><div class="spacer"><table id="t1"><tr><td class="typeheader" colspan="4">Result Set (2 items)</td></tr><tr><th title="System.Int32">ActivityCount</th><th title="System.Int32">ActivityComplete</th><th title="System.String">ImagePath</th><th title="System.String">SubjectTitle</th></tr><tr><td class="n">25</td><td class="n">3</td><td>Subject 1.png</td><td>Subject 1</td></tr><tr><td class="n">1</td><td class="n">1</td><td>Subject 2.png</td><td>Subject 2</td></tr><tr><td title="Total=26
Average=13" class="columntotal">26</td><td title="Total=4
Average=2" class="columntotal">4</td><td title="Totals" class="columntotal"></td><td title="Totals" class="columntotal"></td></tr></table></div></body>
</html>
my linq looks like this:
from x in (
(from Act in Activities
join AOU in UserActivityOutcomes on Act.ActivityID equals AOU.ActivityID into AOU_join
from AOU in AOU_join.DefaultIfEmpty()
join ActNA in Activities on AOU.ActivityID equals ActNA.ActivityID into ActNA_join
from ActNA in ActNA_join.DefaultIfEmpty()
join Cat in Categories on AOU.Activity.CategoryID equals Cat.CategoryID into Cat_join
from Cat in Cat_join.DefaultIfEmpty()
join Sub in Subjects on Cat.SubjectID equals Sub.SubjectID into Sub_join
from Sub in Sub_join.DefaultIfEmpty()
group new {Sub, AOU, Act,ActNA} by new {
Sub.SubjectTitle,
Sub.SubjectImageName
} into g
select new {
ActivityCount = g.Distinct().Count(), //g.Count(),
ActivityComplete = g.Sum(p => (
(p.AOU.OutcomeID == 1 ||
p.AOU.OutcomeID == 3)&&
p.AOU.ActivityUserID == 23 ? 1 : 0)),
ImagePath = g.Key.SubjectImageName,
SubjectTitle = g.Key.SubjectTitle
}))
select new {
x.ActivityCount,
x.ActivityComplete,
x.ImagePath,
x.SubjectTitle
}
LINQ full outer join is tricky. The only way it could be simulated is by union of left outer join and right antijoin. Here is IMO the LINQ equivalent of your SQL query:
var query =
// AOU full join Act
(from e in (from AOU in UserActivityOutcomes
join Act in Activities on AOU.ActivityID equals Act.ActivityID into Act_join
from Act in Act_join.DefaultIfEmpty()
select new { AOU, Act })
.Concat
(from Act in Activities
join AOU in UserActivityOutcomes on Act.ActivityID equals AOU.ActivityID into AOU_join
from AOU in AOU_join.DefaultIfEmpty()
where AOU == null
select new { AOU, Act })
let AOU = e.AOU
let Act = e.Act
// left join Cat
join Cat in Categories on Act.CategoryID equals Cat.CategoryID into Cat_join
from Cat in Cat_join.DefaultIfEmpty()
// left join Sub
join Sub in Subjects on Cat.SubjectID equals Sub.SubjectID into Sub_join
from Sub in Sub_join.DefaultIfEmpty()
group new { Sub, AOU, Act } by new { Sub.SubjectTitle, Sub.SubjectImageName } into g
select new
{
ActivityCount = g.Where(e => e.Act != null).Select(e => e.Act.ActivityID).Distinct().Count(),
ActivityComplete = g.Sum(e => (e.AOU.OutcomeID == 1 || e.AOU.OutcomeID == 3) && e.AOU.ActivityUserID == 1 ? 1 : 0),
ImagePath = g.Key.SubjectImageName,
SubjectTitle = g.Key.SubjectTitle
};

Left outter join linq

How do i change the training events into a left outer join in training events im very basic at linq so excuse my ignorance its not retrieve records that don't have any trainnevent reference attached to it
var q = from need in pamsEntities.EmployeeLearningNeeds
join Employee e in pamsEntities.Employees on need.EmployeeId equals e.emp_no
join tevent in pamsEntities.TrainingEvents on need.TrainingEventId equals tevent.RecordId
where need.EmployeeId == employeeId
where need.TargetDate >= startdate
where need.TargetDate <= enddate
orderby need.TargetDat
It's best to use where in combination with DefaultIfEmpty.
See here: LEFT JOIN in LINQ to entities?
var query2 = (
from users in Repo.T_Benutzer
from mappings in Repo.T_Benutzer_Benutzergruppen.Where(mapping => mapping.BEBG_BE == users.BE_ID).DefaultIfEmpty()
from groups in Repo.T_Benutzergruppen.Where(gruppe => gruppe.ID == mappings.BEBG_BG).DefaultIfEmpty()
//where users.BE_Name.Contains(keyword)
// //|| mappings.BEBG_BE.Equals(666)
//|| mappings.BEBG_BE == 666
//|| groups.Name.Contains(keyword)
select new
{
UserId = users.BE_ID
,UserName = users.BE_User
,UserGroupId = mappings.BEBG_BG
,GroupName = groups.Name
}
);
var xy = (query2).ToList();
Which is equivalent to this select statement:
SELECT
T_Benutzer.BE_User
,T_Benutzer_Benutzergruppen.BEBG_BE
-- etc.
FROM T_Benutzer
LEFT JOIN T_Benutzer_Benutzergruppen
ON T_Benutzer_Benutzergruppen.BEBG_BE = T_Benutzer.BE_ID
LEFT JOIN T_Benutzergruppen
ON T_Benutzergruppen.ID = T_Benutzer_Benutzergruppen.BEBG_BG

How can I perform a left join and exclude results that match a subquery in LINQ?

Need to convert this sql query to LINQ
SELECT *
FROM
parcels p
LEFT JOIN leases l ON p.parcels_pk = l.parcels_fk
WHERE
l.parcels_fk IS NULL
AND p.parcels_pk NOT IN (SELECT parcels_fk FROM application_parcels)
ORDER BY parcel
tried this:
var qry = from p in db.Parcels
join l in db.Leases on p.Id equals l.pk_parcel
where l.pk_parcel == null
&& !(from ap in db.ApplicationParcels
select ap.ParcelId).Contains(p.Id)
orderby p.Name
// SELECT * FROM parcels
var result = from p in parcels
// LEFT JOIN leases ON p.parcels_pk = l.parcels_fk
join llj in leases on p.parcels_pk equals llj.parcels_fk into lj
from l in lj.DefaultIfEmpty()
// WHERE l.parcels_fk IS NULL
where l.parcels_fk == null
// AND p.parcels_pk NOT IN (...)
&& !application_parcels.Any(x => x.parcels_fk == p.parcels_pk)
// ORDER BY [p.]parcel
order by p.parcel
select new { parcel = p, lease = l };
Assuming i have your schema correct.
But in the future:
First supply what you've tried (show an effort).
Have a look at LINQPad, it's very helpful.