need help translating CTE query into linq (not recursive) - linq

Not sure how easy this is to answer just by looking at a sample SQL query when you don't know the data behind it, but I'll try anyway. This is a SQL query meant to list files in a source control db--showing the source file path side-by-side with its most recent checked-in version path:
WITH [recentCheckins] AS (
SELECT [SourceFileID], MAX([Version]) AS [LatestVersion]
FROM [Checkin]
GROUP BY [SourceFileID]
) SELECT
[sf].[Path], -- current version
[ci].[ArchivePath] -- most recent previous checkin
FROM
[recentCheckins]
INNER JOIN [SourceFile] [sf] ON [recentCheckins].[SourceFileID]=[sf].[ID]
INNER JOIN [Checkin] [ci] ON
[recentCheckins].[SourceFileID]=[ci].[SourceFileID] AND
[recentCheckins].[LatestVersion]=[ci].[Version]
This is the most I could do:
var query2 =
from latestCheckins in (
from checkin in _project.Checkin
group checkin by checkin.SourceFileID into results
select new
{
SourceFileID = results.Key,
LatestCheckinVersion = results.Max(s => s.Version)
})
join sourceFile in _project.SourceFile on latestCheckins.SourceFileID equals sourceFile.ID
join checkins in _project.Checkin on // fails on this line, does not like join keyword here
new { latestCheckins.SourceFileID, latestCheckins.LatestCheckinVersion }
equals new { checkins.SourceFileID, checkins.Version }
select new
{
Filename = sourceFile.Path,
CheckinDate = checkins.DateCreated,
TaskID = checkins.TaskID,
Comments = checkins.Comments,
Version = latestCheckins.LatestCheckinVersion.ToString(),
NewFile = _project.GetSourceFilename(sourceFile.Path),
OldFile = checkins.ArchivePath,
ID = sourceFile.ID
};

got this to work by breaking it into separate queries, as suggested by Gert above.

Related

Insert records using select in LINQ

How can we convert following query to LINQ
INSERT INTO License (PersonID, LicenseState, LicenseNumber, LicenseYear)
SELECT p.PersonID,
s.LicenseState,
s.LicenseNumber,
s.LicenseYear
FROM SourceData s
JOIN Person p
ON s.UserID = p.DomainAccountName
WHERE s.isActive = 1
var query = from s in db.SourceData
join p in db.Person on s.UserId equals p.DomainAccountName
where s.IsActive
select new License
{
PersonID = p.PersonID,
LicenseState = s.LicenseState,
LicenseNumber = s.LicenseNumber,
LicenseYear = s.LicenseYear
};
db.Licenses.AddRange(query);
That will actually give you one SQL query, and a bunch of individual SQL INSERTS. Alternately, you could use the Z.EntityFramework.Plus.EFCore nuget package, and use the code
var query = ... (same)...
db.Licenses.InsertFromQuery(query);
which should use the single SQL statement you posted.
UPDATE: I originally confused the retail/licensed Z.EntityFramework.Extensions.EFCore with the free/open-source Z.EntityFramework.Plus.EFCore package. Code above has been updated.
If you care about performance, you don't have to load anything to the client. It is how EF Core works right now, if you want to insert something - you have to feed ChangeTracker with new records.
I would suggest EF Core extension linq2db.EntityFrameworkCore which generates exactly the same query as in question but via LINQ. Note that I'm one of the creators.
Then you can do the following:
var query =
from s in db.SourceData
join p in db.Person on s.UserId equals p.DomainAccountName
where s.IsActive
select new License
{
PersonID = p.PersonID,
LicenseState = s.LicenseState,
LicenseNumber = s.LicenseNumber,
LicenseYear = s.LicenseYear
};
await query.InsertAsync(db.License.ToLinqToDBTable(), x => x);

Linq Left Outer Join Two Tables on Two Fields

How do I left outer join two tables on two fields in linq?
I have a sql:
select a.*, b.* from courselist as a
left outer join Summary as b
on a.subject = b.Subject and a.catalog =
b.Catalogno
where a.degree_id = 1
order by a.sequenceNo
Below is my linq query, but there is error underline "join", failed in the call to "Groupjoin". I don't know how to correct that.
var searchResults = (from a in db.courselist
join b in db.Summary on
new { a.subject,a.catalog } equals
new { b.Subject, b.Catalogno } into ab
where a.degree_id == 1
orderby a.degree_sequenceNo
from b in ab.DefaultIfEmpty()
select new
{
Courselist = a,
Summary = b
}
).ToList();
Thanks.
I've checked your code again,
I found it's fault
you just need to specify join parameters name like this:
new { suject = a.subject, catalog = a.catalog } equals
new { suject = b.subject, catalog = b.Catalogno } into ab
It seems you are missing the reference, the query doesn't have an error
try to use this:
using System.Linq;
The main issue when people start using LINQ is that they keep thinking in the SQL way, they design the SQL query first and then translate it to LINQ. You need to learn how to think in the LINQ way and your LINQ query will become neater and simpler. For instance, in your LINQ you don't need joins. You should use Associations/Navigation Properties instead. Check this post for more details.
There should be a relationship between courselist and Summary, in which case, you can access Summary through courselist like this:
var searchResults = (from a in db.courselist
where a.degree_id == 1
orderby a.degree_sequenceNo
select new {
Courselist = a,
Summary = a.Summary
}).ToList();
If there is no relationship between the two, then you should reconsider your design.

Help for translate c# Linq query with 2 group by into vb.net linq query

Hello everyone,
I tried and tried to make this query in vb.net, but I can not.
I do not understand if I have to use two groups, and if so, how do I use them.
This is a query that is in the project - tutorial Tailspin SpyWorks
and should serve to show the 5 most popular products.
I do not understand really how to do.
var query = (from ProductOrders in db.OrderDetails
join SelectedProducts in db.Products on ProductOrders.ProductID
equals SelectedProducts.ProductID
group ProductOrders by new
{
ProductId = SelectedProducts.ProductID,
ModelName = SelectedProducts.ModelName
} into grp
select new
{
ModelName = grp.Key.ModelName,
ProductId = grp.Key.ProductId,
Quantity = grp.Sum(o => o.Quantity)
} into orderdgrp
where orderdgrp.Quantity > 0
orderby orderdgrp.Quantity descending
select orderdgrp).Take(5);
I tried to do the translation but I can not find documentation that helps me understand how do I manage two groups.
Dim query = (From ProductOrders in db.OrderDetails
Join SelectedProducts in db.Products On
ProductOrders.ProductID Equals SelectedProducts.ProductID
Group ProductOrders By New With
{
.ProductId = SelectedProducts.ProductID,
.ModelName = SelectedProducts.ModelName
} into grp
In fact from now on I can not go on
If someone can please help me out
Thanks a lot
Fabrizio
Im not an expert of VB language, but the following code is syntactically correct:
Dim query = (From ProductOrders In Products
Join SelectedProducts In SelProducts On ProductOrders.ProductId Equals SelectedProducts.ProductId
Group ProductOrders By Key = New With {
.ProductId = SelectedProducts.ProductId,
.ModelName = SelectedProducts.ModelName
} Into grp = Group
Select orderdgrp = New With
{
.ModelName = Key.ModelName,
.ProductId = Key.ProductId,
.Quantity = grp.Sum(Function(o) o.Quantity)
}
Where orderdgrp.Quantity > 0
Order By orderdgrp.Quantity Descending
Select orderdgrp).Take(5)
Verify that the query is also semantically correct.

How to implement a left outer join in the Entity Framework

I have the following SQL query:-
select distinct * from dbo.Profiles profiles
left join ProfileSettings pSet on pSet.ProfileKey = profiles.ProfileKey
left join PlatformIdentities pId on pId.ProfileKey = profiles.Profilekey
I need to convert it to a LinqToEntities expression. I have tried the following:-
from profiles in _dbContext.ProfileSet
let leftOuter = (from pSet in _dbContext.ProfileSettingSet
select new
{
pSet.isInternal
}).FirstOrDefault()
select new
{
profiles.ProfileKey,
Internal = leftOuter.isInternal,
profiles.FirstName,
profiles.LastName,
profiles.EmailAddress,
profiles.DateCreated,
profiles.LastLoggedIn,
};
The above query works fine because I haven't considered the third table "PlatformIdentities". Single left outer join works with what I have done above. How do I include PlatformIdentities (the 3rd table) ? I basically want to translate the SQL query I specified at the beginning of this post (which gives me exactly what I need) in to LinqToEntities.
Thanks
Let me know if you want to select something different, but a true join is below
from p in _dbContext.ProfileSet
join ps in _dbContext.ProfileSettings on p.ProfileKey = ps.ProfileKey into a
join pi in _dbContext.PlatformIdentities on p.ProfileKey = pi.ProfileKey into b
select new
{
profiles.ProfileKey,
profiles.FirstName,
profiles.LastName,
profiles.EmailAddress,
profiles.DateCreated,
profiles.LastLoggedIn,
PlatformSettings = a.Select(x=>x),
PlatformIdentities = b.Select(y=>y)
}

Stuck on a subquery that is grouping, in Linq`

I have some Linq code and it's working fine. It's a query that has a subquery in the Where clause. This subquery is doing a groupby. Works great.
The problem is that I don't know how to grab one of the results from the subquery out of the subquery into the parent.
Frst, here's the code. After that, I'll expplain what piece of data i'm wanting to extract.
var results = (from a in db.tblProducts
where (from r in db.tblReviews
where r.IdUserModified == 1
group r by
new
{
r.tblAddress.IdProductCode_Alpha,
r.tblAddress.IdProductCode_Beta,
r.tblAddress.IdProductCode_Gamma
}
into productGroup
orderby productGroup.Count() descending
select
new
{
productGroup.Key.IdProductCode_Alpha,
productGroup.Key.IdProductCode_Beta,
productGroup.Key.IdProductCode_Gamma,
ReviewCount = productGroup.Count()
}).Take(3)
.Any(
r =>
r.IdProductCode_Alpha== a.IdProductCode_Alpha&&
r.IdProductCode_Beta== a.IdProductCode_Beta&&
r.IdProductCode_Gamma== a.IdProductCode_Gamma)
where a.ProductFirstName == ""
select new {a.IdProduct, a.FullName}).ToList();
Ok. I've changed some field and tables names to protect the innocent. :)
See this last line :-
select new {a.IdProduct, a.FullName}).ToList();
I wish to include in that the ReviewCount (from the subquery). I'm jus not sure how.
To help understand the problem, this is what the data looks like.
Sub Query
IdProductCode_Alpha = 1, IdProductCode_Beta = 2, IdProductCode_Gamma = 3, ReviewCount = 10
... row 2 ...
... row 3 ...
Parent Query
IdProduct = 69, FullName = 'Jon Skeet's Wonder Balm'
So the subquery grabs the actual data i need. The parent query determines the correct product, based on the subquery filters.
EDIT 1: Schema
tblProducts
IdProductCode
FullName
ProductFirstName
tblReviews (each product has zero to many reviews)
IdProduct
IdProductCode_Alpha (can be null)
IdProductCode_Beta (can be null)
IdProductCode_Gamma (can be null)
IdPerson
So i'm trying to find the top 3 products a person has done reviews on.
The linq works perfectly... except i just don't know how to include the COUNT in the parent query (ie. pull that result from the subquery).
Cheers :)
Got it myself. Take note of the double from at the start of the query, then the Any() being replaced by a Where() clause.
var results = (from a in db.tblProducts
from g in (
from r in db.tblReviews
where r.IdUserModified == 1
group r by
new
{
r.tblAddress.IdProductCode_Alpha,
r.tblAddress.IdProductCode_Beta,
r.tblAddress.IdProductCode_Gamma
}
into productGroup
orderby productGroup.Count() descending
select
new
{
productGroup.Key.IdProductCode_Alpha,
productGroup.Key.IdProductCode_Beta,
productGroup.Key.IdProductCode_Gamma,
ReviewCount = productGroup.Count()
})
.Take(3)
Where(g.IdProductCode_Alpha== a.IdProductCode_Alpha&&
g.IdProductCode_Beta== a.IdProductCode_Beta&&
g.IdProductCode_Gamma== a.IdProductCode_Gamma)
where a.ProductFirstName == ""
select new {a.IdProduct, a.FullName, g.ReviewCount}).ToList();
While I don't understand LINQ completely, but wouldn't the JOIN work?
I know my answer doesn't help but it looks like you need a JOIN with the inner table(?).
I agree with shahkalpesh, both about the schema and the join.
You should be able to refactor...
r => r.IdProductCode_Alpha == a.IdProductCode_Alpha &&
r.IdProductCode_Beta == a.IdProductCode_Beta &&
r.IdProductCode_Gamma == a.IdProductCode_Gamma
into an inner join with tblProducts.

Resources