Converting SQL query into LINQ - not working - c#

The SQL query I'm trying to convert is:
select p.PhoneNumber_Id, p.State, p.Created
from PhoneNumberServiceItems p
join PhoneNumbers on p.PhoneNumber_Id = PhoneNumbers.Id
inner join (
select PhoneNumber_Id, max(Created) as MaxDate
from PhoneNumberServiceItems
group by PhoneNumber_Id
) tm on p.PhoneNumber_Id = tm.PhoneNumber_Id and p.Created = tm.MaxDate
where PhoneNumbers.NumberRangeId = {Id}
And the LINQ code I've ended up with is below, however this isn't working:
var res =
from serviceItems in _db.PhoneNumberServiceItems
join nums in _db.PhoneNumbers on serviceItems.PhoneNumber_Id equals nums.Id
where nums.NumberRangeId == id
join serviceGroup in (from ps in _db.PhoneNumberServiceItems
group ps by ps.PhoneNumber_Id into numGroup
//join tm in _db.PhoneNumbers on psg.FirstOrDefault().PhoneNumber_Id equals tm.Id
select new
{
NumId = numGroup.FirstOrDefault().PhoneNumber_Id,
MaxDate = numGroup.Max(i => i.Created)
}) on new { PNId = serviceItems.PhoneNumber_Id, serviceCreated = serviceItems.Created } equals new { PNId = serviceGroup.NumId, serviceCreated = serviceGroup.MaxDate }
select new
{
State = serviceItems.State,
NumId = serviceGroup.NumId,
Created = serviceGroup.MaxDate
};
I'm aware my LINQ is wrong, but I can't put my finger on what it is I'm doing differently. Any help would be appreciated.
Edit: This is the compiled SQL generated from the LINQ
SELECT
[Extent1].[State] AS [State],
[Project4].[C1] AS [C1],
[Project4].[C2] AS [C2]
FROM [dbo].[PhoneNumberServiceItems] AS [Extent1]
INNER JOIN [dbo].[PhoneNumbers] AS [Extent2] ON [Extent1].[PhoneNumber_Id] = [Extent2].[Id]
INNER JOIN (SELECT
[Project3].[C1] AS [C1],
(SELECT
MAX([Extent5].[Created]) AS [A1]
FROM [dbo].[PhoneNumberServiceItems] AS [Extent5]
WHERE [Project3].[PhoneNumber_Id] = [Extent5].[PhoneNumber_Id]) AS [C2]
FROM ( SELECT
[Distinct1].[PhoneNumber_Id] AS [PhoneNumber_Id],
(SELECT TOP (1)
[Extent4].[PhoneNumber_Id] AS [PhoneNumber_Id]
FROM [dbo].[PhoneNumberServiceItems] AS [Extent4]
WHERE [Distinct1].[PhoneNumber_Id] = [Extent4].[PhoneNumber_Id]) AS [C1]
FROM ( SELECT DISTINCT
[Extent3].[PhoneNumber_Id] AS [PhoneNumber_Id]
FROM [dbo].[PhoneNumberServiceItems] AS [Extent3]
) AS [Distinct1]
) AS [Project3] ) AS [Project4] ON ([Extent1].[PhoneNumber_Id] = [Project4].[C1]) AND ([Extent1].[Created] = [Project4].[C2])
WHERE [Extent2].[NumberRangeId] = {id}

This is linq equivalent of your query.
var res = from s in PhoneNumberServiceItems
join p in PhoneNumbers on s.PhoneNumber_Id equals p.Id
join tm in ( from p1 in PhoneNumberServiceItems
group p1 by p1.PhoneNumber_Id into p_g
select new {PhoneNumber_Id = p_g.Key,MaxDate = p_g.Max(i=> i.Created) } )
on new {Created = s.Created, PhoneNumber_Id = s.PhoneNumber_Id}
equals new { Created = tm.MaxDate, PhoneNumber_Id = tm.PhoneNumber_Id}
where p.NumberRangeId == {Id}
select new
{
s.PhoneNumber_Id,
s.State,
s.Created
};

Try following which is much simpler :
var res = (from nums in _db.PhoneNumbers.Where(x => NumberRangeId == id)
join serviceItems in _db.PhoneNumberServiceItems on nums.PhoneNumber_Id equals serviceItems.Id
select new {serviceItems = serviceItems, nums = nums})
.OrderByDescending(x => x.serviceItems.Created)
.GroupBy(x => x.nums.PhoneNumber_Id)
.Select(x => x.First())
.Select(x => new {Id = x.nums.PhoneNumber_Id, state = x.serviceItems.State, maxDate = x.serviceItems.Created})
.ToList();

var recentPhoneNos= from psi in _db.PhoneNumberServiceItems
group psi by psi .PhoneNumber_Id into psiTemp
select new {
PhoneNumber_Id = psiTemp.Key,
MaxDate = psiTemp.Max(i=> i.Created)
};
var res=from serviceItems in _db.PhoneNumberServiceItems
join nums in _db.PhoneNumbers on serviceItems.PhoneNumber_Id equals nums.Id
join serviceGroup in recentPhoneNos on nums.Id equals serviceGroup .PhoneNumber_Id
where nums.NumberRangeId == id && serviceGroup.MaxDate
select new {
State = serviceItems.State,
NumId = serviceGroup.NumId,
Created = serviceGroup.MaxDate
} ;

Related

Particular Query in Linq It does not perform the same thing as an inner join in SQL Server

This query is being carried out to take the zone and category names from the respective Product-related tables.
SELECT
Categoria.NombreCategoria,
Zona.ZonaGrupo,
p.NombreProducto,
p.ProductoTiene,
p.RealizadosEvento,
p.FechaInicial,
p.FechaFin
FROM
Productos p
INNER JOIN
Categoria ON p.CategoriaId = Categoria.Id
INNER JOIN
Zona ON p.ZonaId = Zona.ZonaId
The result of the SQL query returns the 1000 records that the products table must have with their zones and categories.
When doing the following in linq, it returns only 8 records ...
IQueryable<ProductosViewModel> ProductosMaped =
from p in Db.Productos
join g in Db.Zona on p.ZonaId equals g.ZonaId
join acr in Db.Categoria on p.CategoriaId equals acr.Id
select new ProductosViewModel
{
Categoria = acr.NombreCategoria,
ZonaGrupo = g.ZonaGrupo,
NombreProducto = p.NombreProducto,
ProductoTiene = p.ProductoTiene,
RealizadosEvento = p.RealizadosEvento,
FechaInicial = p.FechaInicial,
FechaFin = p.FechaFin,
};
I only need to link these 2 tables so that list only shows me CategoryName and ZoneName or Group Zone.
Better idea: Use Include with navigation properties:
List<ProductosViewModel> list = await this.Db.Productos
.Include( p => p.Zona )
.Include( p => p.Categoria )
.Where( p => p.Categoria != null && p.Zona != null ) // <-- This step may be optional depending on your database.
.Select( p => new ProductosViewModel
{
Categoria = p.Categoria.NombreCategoria,
ZonaGrupo = p.Zona.ZonaGrupo,
NombreProducto = p.NombreProducto,
ProductoTiene = p.ProductoTiene,
RealizadosEvento = p.RealizadosEvento,
FechaInicial = p.FechaInicial,
FechaFin = p.FechaFin,
} )
.ToListAsync()
.ConfigureAwait(false);

Linq query does not return data

I have the following query in SQL which returns 5 rows of data:
SELECT DISTINCT c.Id, c.FirstName, c.LastName, c.PhoneNumber, 'Waiting to be sent'
FROM DistributionGroupMembers dgm
JOIN Contacts c on dgm.ContactId = c.Id
JOIN DistributionGroups dg on dgm.DistributionGroupId = dg.Id
WHERE dg.Id IN (
SELECT DistributionGroupId
FROM DistributionGroupInSms
WHERE SmsId = 40
)
When I try to run the adequate query in C# using LINQ it won't return anything:
int[] groupIDs = await _db.DistributionGroupInSms.Where(dgis => dgis.SmsId == message.Id).Select(g => g.Id).ToArrayAsync();
var recipients = await (from dgm in _db.DistributionGroupMembers
join c in _db.Contacts on dgm.ContactId equals c.Id
join dg in _db.DistributionGroups on dgm.DistributionGroupId equals dg.Id
where groupIDs.Contains(dg.Id)
select new
{
ID = c.Id,
FN = c.FirstName,
LN = c.LastName,
PN = c.PhoneNumber,
SR = "Waiting to be sent"
}).Distinct().ToListAsync();
What am I doing wrong?
Can you simply do a join:
int[] groupIDs = await _db.DistributionGroupInSms.Where(dgis => dgis.SmsId == message.Id).Select(g => g.Id).ToArrayAsync();
var recipients = await (from dgm in _db.DistributionGroupMembers
join c in _db.Contacts on dgm.ContactId equals c.Id
join dg in _db.DistributionGroups on dgm.DistributionGroupId equals dg.Id
join gIds in groupIDs on gIds equals dg.Id
select new
{
ID = c.Id,
FN = c.FirstName,
LN = c.LastName,
PN = c.PhoneNumber,
SR = "Waiting to be sent"
}).Distinct().ToListAsync();
I figured it out, in the select clause by getting the groupIDs I selected Id instead of another field in the table called DistributionGroupId. Thanks everyone for the input

multiple join clause ended with a group join LINQ

I working on an app with a SQLite database, now I want to select information from multiple tables using linq, here it is what I did:
from c in dataContext.Convention
join e in dataContext.Engineer on c.Engineer equals e.Code
join o in dataContext.Owner on c.Owner equals o.Code
join t in dataContext.ProjectType on c.ProjectType equals t.Id
join cs in dataContext.ConventionState on c.State equals cs.Id
join sc in dataContext.SiteControl on c.Code equals sc.CodeCv
join pc in dataContext.PlanControl on c.Code equals pc.CodeCv
join scs in dataContext.SiteState on sc.State equals scs.Id
join pcs in dataContext.PlanState on pc.State equals pcs.Id
join rcs in dataContext.ReceptionState on sc.Reception equals rcs.Id
join b in dataContext.Bill on c.Code equals b.CodeCv
where cs.Abr == "EC"
group new { c, e, o, t, scs, pcs, rcs, b } by new
{ c.Code, c.NumSeq, c.Year, c.TotalAmount, c.Title, e.LastName, e.FirstName, o.Name,
tprjt = t.Abr,
scState = scs.Abr,
pcState = pcs.Abr,
rcState = rcs.Abr
} into cvgrp
select new
{
Code = cvgrp.Key.Code,
N_Seq = cvgrp.Key.NumSeq,
Exercice = cvgrp.Key.Year,
Intitulé = cvgrp.Key.Title,
Ingenieur = cvgrp.Key.LastName + " " + cvgrp.Key.FirstName,
MaitreOuvrage = cvgrp.Key.Name,
TypeProjet = cvgrp.Key.tprjt,
CtrlPlan = cvgrp.Key.pcState,
CtrlChantier = cvgrp.Key.scState,
Reception = cvgrp.Key.rcState,
Montant = cvgrp.Key.TotalAmount,
MontantFacturé = cvgrp.Sum(x => x.b.Amount),
MontantRestant = cvgrp.Key.TotalAmount - cvgrp.Sum(x => x.b.Amount),
MontantCréance = cvgrp.Sum(x => x.b.IsPaid == "False" ? x.b.Amount : 0.0 )
}
It seems working but I really don't understand clearly what I did especially in the group by clause. If I add an into clause after the joins before the group by the identifier will work as a table with all the tables joined ?.
I need some explanation to understand linq more.
Thank you in advance.

Check whether object NOT exists in another table in LINQ?

I have a query in entity framework which gets some messages from tables.
var ur = (from m in en.Messages
join mb in en.aspnet_Membership on m.FromUserId equals mb.UserId
join urs in en.UserProfiles on mb.UserId equals urs.UserId
join g in en.Groups on m.ToUserId equals g.GroupId
join ug in en.UserInGroups on g.GroupId equals ug.GroupId
where ug.UserId == userId
select new
{
InboxId = m.MessageId,
FromUser = urs.RaveName.Trim(),
CreatedOn = m.CreatedOn
}
).Concat(
// msg is not deleted
from m in en.Messages
join mb in en.aspnet_Membership on m.FromUserId equals mb.UserId
join urs in en.UserProfiles on mb.UserId equals urs.UserId
where m.ToUserId == userId
select new
{
InboxId = m.MessageId
,
FromUser = urs.RaveName.Trim()
,
CreatedOn = m.CreatedOn
}
);
I have another table which shows whether the message is used:
var msg = (from m in en.MessagesUsed
where m.UserId == userId
select m
);
Now, I need to check: Is there a message in 'ur' that is not in 'msg'? In T-SQL, we can use:
SELECT 1
FROM ur
WHERE NOT EXISTS (SELECT 1 FROM msg WHERE msg.Id = ur.InboxId AND msg.FromUser = ur.FromUser AND msg.CreatedOn = ur.CreatedOn)
to check this. But how to do it in LINQ?
Thanks

Linq To Sql Nested Select

This is the SQL query I am trying to write with LINQ:
SELECT pd.Description, pd.Name, pd.SKU, pt.FileName,
(SELECT ISNULL(M1.parent, '') + '/' + M2.parent + '/' + M2.slug
FROM seo AS M1
JOIN seo AS M2
ON M1.Slug = M2.Parent
WHERE M2.SeoId = pd.seoId) as Url
FROM SEO seo
INNER JOIN Products p on seo.SeoID = p.SeoID
INNER JOIN RelatedProducts rp on p.ProductID = rp.ProductID
INNER JOIN Products pd on rp.RelatedID = pd.ProductID
INNER JOIN ProductPhotos pp on pd.ProductID = pp.ProductID
INNER JOIN Photos pt on pp.PhotoID = pt.PhotoID
WHERE seo.slug = 'SlugValue'
This is the LINQ I have:
_database.SEODataSource
.Join(_database.ProductDataSource, seo => seo.SeoID, p => p.SeoID, (seo, p) => new { seo, p })
.Join(_database.RelatedProductDataSource, #t => #t.p.ProductID, rp => rp.ProductID, (#t, rp) => new { #t, rp })
.Join(_database.ProductDataSource, #t => #t.rp.RelatedID, pd => pd.ProductID, (#t, pd) => new { #t, pd })
.Join(_database.ProductPhotoDataSource, #t => #t.pd.ProductID, pp => pp.ProductID, (#t, pp) => new { #t, pp })
.Join(_database.PhotoDataSource, #t => #t.pp.PhotoID, pds => pds.PhotoID, (#t, pds) => new { #t, pds })
.Where(#t => #t.#t.#t.#t.#t.seo.Slug == slug)
.Select(#t => new ProductLinkDTO
{
ProductDesc = #t.#t.#t.pd.Description,
ProductName = #t.#t.#t.pd.Name,
ProductSku = #t.#t.#t.pd.SKU,
ProductImageName = #t.pds.FileName,
ProductUrl = (_database.SEODataSource.Join(_database.SEODataSource, seo1 => seo1.SeoID, seo2 => seo2.SeoID, (seo1, seo2) => new {seo1, seo2})
.Where(#t1 => #t1.seo2.SeoID == #t.#t.#t.#t.#t.seo.SeoID)
.Select(#t1 => #t1.seo1.Parent ?? "" + "/" + #t1.seo2.Parent + "/" + #t1.seo2.Slug)).FirstOrDefault()
}).ToList());
This is the query it produces:
SELECT [t3].[Name] AS [ProductName], [t3].[Description] AS [ProductDesc], [t3].[SKU] AS [ProductSku], [t5].[FileName]
AS [ProductImageName], (
SELECT TOP (1) [t8].[value]
FROM (
SELECT COALESCE([t6].[Parent],((#p1 + [t7].[Parent]) + #p2) + [t7].[Slug]) AS [value], [t7].[SeoID]
FROM [dbo].[SEO] AS [t6]
INNER JOIN [dbo].[SEO] AS [t7] ON [t6].[SeoID] = [t7].[SeoID]
) AS [t8]
WHERE [t8].[SeoID] = [t0].[SeoID]
) AS [ProductUrl]
FROM [dbo].[SEO] AS [t0]
INNER JOIN [dbo].[Products] AS [t1] ON ([t0].[SeoID]) = [t1].[SeoID]
INNER JOIN [dbo].[RelatedProducts] AS [t2] ON [t1].[ProductID] = [t2].[ProductID]
INNER JOIN [dbo].[Products] AS [t3] ON [t2].[RelatedID] = [t3].[ProductID]
INNER JOIN [dbo].[ProductPhotos] AS [t4] ON [t3].[ProductID] = [t4].[ProductID]
INNER JOIN [dbo].[Photos] AS [t5] ON [t4].[PhotoID] = [t5].[PhotoID]
WHERE [t0].[Slug] = #p0',N'#p0 nvarchar(4000),#p1 nvarchar(4000),#p2
nvarchar(4000)',#p0=N'KBUIT4255E-42in-Masterpiece-Side-By-Side',#p1=N'/',#p2=N'/'
Any idea what I am doing wrong?
By changing this:
.Select(#t1 => #t1.seo1.Parent ?? "" + "/" + #t1.seo2.Parent + "/" + #t1.seo2.Slug)).FirstOrDefault()
To:
.Select(#t1 => String.Concat(#t1.seo1.Parent ?? "", "/", #t1.seo2.Parent, "/", #t1.seo2.Slug))).SingleOrDefault()
The correct SQL was generated.

Categories

Resources