How can I transalte SQL Query to LINQ - c#

I trying to translate SQL Query to Linq statement:
SELECT f.BarcodeNumber,m.Name, f.Model, SUM(f.Quantity) as FoundedAssetsQty, ISNULL(a.Quantity,0) as AssetQty
FROM [InventoryDB].[dbo].[FoundedAssets] f
join [InventoryDB].[dbo].[PhisicalStockCheckSheets] p on p.ID = f.PhisicalStockCheckSheetId
join [InventoryDB].[dbo].[Inventories] i on i.ID = p.InventoryId
left join [InventoryDB].[dbo].[Assets] a on a.BarcodeNumber = f.BarcodeNumber
join [InventoryDB].[dbo].[Manufacturers] m on m.ID = f.ManufacturerId
where p.InventoryId = 10
group by f.BarcodeNumber, a.Quantity, f.Model, m.Name
I have no idea how to do it. I tried many ways but I fail. Could anyone help me?

I tried to use Linqer, but when I configure the connection it fails, so I write the linq instruction myself. Finally I found the answer. I have not mentioned the relations between entities but it is not important here.
var summary = _context.FoundedAssets.Include(f => f.Manufacturer).
Include(f => f.Asset).
Include(f => f.PhisicalStockCheckSheet).ThenInclude(f => f.Inventory).
Where(f => f.PhisicalStockCheckSheet.Inventory.ID == id).
Select(x => new InventorySummaryModel()
{
BarcodeNumber = x.BarcodeNumber.Value,
ManufacturerName = x.Manufacturer.Name,
Model = x.Model,
AssetsQuantity = x.Asset.Quantity,
FoundedAssetQuantity = x.Quantity
}).ToList();
var groupedSummary = summary.GroupBy(x => x.BarcodeNumber).Select(x => new InventorySummaryModel()
{
BarcodeNumber = x.First().BarcodeNumber,
ManufacturerName = x.First().ManufacturerName,
Model = x.First().Model,
FoundedAssetQuantity = x.Sum(a => a.FoundedAssetQuantity),
AssetsQuantity = x.First().AssetsQuantity
}).ToList();
Maybe exists any easier approach but this one works properly.

Related

How to write linq query for this sql statement

How would you write a linq query with the following SQL statement. I've tried several methods referenced on stackoverflow but they either don't work with the EF version I'm using (EF core 3.5.1) or the DBMS (SQL Server).
select a.ProductID, a.DateTimeStamp, a.LastPrice
from Products a
where a.DateTimeStamp = (select max(DateTimeStamp) from Products where a.ProductID = ProductID)
For reference, a couple that I've tried (both get run-time errors).
var results = _context.Products
.GroupBy(s => s.ProductID)
.Select(s => s.OrderByDescending(x => x.DateTimeStamp).FirstOrDefault());
var results = _context.Products
.GroupBy(x => new { x.ProductID, x.DateTimeStamp })
.SelectMany(y => y.OrderByDescending(z => z.DateTimeStamp).Take(1))
Thanks!
I understand you would like to have a list of the latest prices of each products?
First of all I prefer to use group by option even over 1st query
select a.ProductID, a.DateTimeStamp, a.LastPrice
from Products a
where a.DateTimeStamp IN (select max(DateTimeStamp) from Products group by ProductID)
Later Linq:
var maxDateTimeStamps = _context.Products
.GroupBy(s => s.ProductID)
.Select(s => s.Max(x => x.DateTimeStamp)).ToArray();
var results = _context.Products.Where(s=>maxDateTimeStamps.Contains(s.DateTimeStamp));
-- all assuming that max datetime stamps are unique
I've managed to do it with the following which replicates the correlated sub query in the original post (other than using TOP and order by instead of the Max aggregate), though I feel like there must be a more elegant way to do this.
var results = from x
in _context.Products
where x.DateTimeStamp == (from y
in _context.Products
where y.ProductID == x.ProductID
orderby y.DateTimeStamp descending
select y.DateTimeStamp
).FirstOrDefault()
select x;
I prefer to break up these queries into IQueryable parts, do you can debug each "step".
Something like this:
IQueryable<ProductOrmEntity> pocoPerParentMaxUpdateDates =
entityDbContext.Products
//.Where(itm => itm.x == 1)/*if you need where */
.GroupBy(i => i.ProductID)
.Select(g => new ProductOrmEntity
{
ProductID = g.Key,
DateTimeStamp = g.Max(row => row.DateTimeStamp)
});
//// next line for debugging..do not leave in for production code
var temppocoPerParentMaxUpdateDates = pocoPerParentMaxUpdateDates.ToListAsync(CancellationToken.None);
IQueryable<ProductOrmEntity> filteredChildren =
from itm
in entityDbContext.Products
join pocoMaxUpdateDatePerParent in pocoPerParentMaxUpdateDates
on new { a = itm.DateTimeStamp, b = itm.ProductID }
equals
new { a = pocoMaxUpdateDatePerParent.DateTimeStamp, b = pocoMaxUpdateDatePerParent.ProductID }
// where
;
IEnumerable<ProductOrmEntity> hereIsWhatIWantItems = filteredChildren.ToListAsync(CancellationToken.None);
That last step, I am putting in an anonymous object. You can put the data in a "new ProductOrmEntity() { ProductID = pocoMaxUpdateDatePerParent.ProductID }...or you can get the FULL ProductOrmEntity object. Your original code, I don't know if getting all columns of the Product object is what you want, or only some of the columns of the object.

C# LINQ to SQL - one to many relationship

I have troubles creating this query in LINQ:
USE Northwind
GO
SELECT emp.FirstName, emp.LastName, tr.TerritoryDescription, reg.RegionDescription
FROM Employees emp
INNER JOIN EmployeeTerritories empt ON empt.EmployeeID = emp.EmployeeID
INNER JOIN Territories tr ON tr.TerritoryID = empt.TerritoryID
INNER JOIN Region reg ON reg.RegionID = tr.RegionID
This is my current creation:
var query = await context
.Employees
.Select(x => new
{
x.FirstName,
x.LastName,
TerritoryId = x.EmployeeTerritories. //cannot access properties
})
.ToListAsync();
But i can't easily access EmployeeTerritories properties, since it's not 1:1 relationship. I accept both clues and full solution to this problem.
Edit
So this is what i currently have:
var query = await context
.Employees
.Select(x => new
{
x.FirstName,
x.LastName,
TerritoryDescription = x.EmployeeTerritories
.Select(et => et.Territory.TerritoryDescription)
.ToList(),
RegionDesicription = x.EmployeeTerritories
.Select(et => et.Territory.Region.RegionDescription)
.ToList()
})
.ToListAsync();
Is there a way to optimize it? RegionDescription is now a list that contains one element, but i don't know how to do it the better way.
Try something like this (assuming you have corresponding relations):
var query = await context
.Employees
.Select(x => new
{
x.Employee.FirstName,
x.Employee.LastName,
TerritoryDescription = x.EmployeeTerritories
.Select(et => et.Territory.TerritoryDescription)
.ToList(),
})
.ToListAsync();
UPD
To flatten in your particular case you can use solution posted by #dhrumil shah(it is more generic one) or try something like that, if you have EmployeeTerritories set up in your context :
var query = await context
.EmployeeTerritories
.Select(et => new
{
et.Employee.FirstName,
et.Employee.LastName,
et.Territory.TerritoryDescription,
et.Territory.Region.RegionDescription
})
.ToListAsync();
(from emp in context.Employees
join empt in context.EmployeeTerritories
on emp.EmployeeID equals empt.EmployeeID
join tr in context.EmployeeTerritories
on empt.TerritoryID equals tr.EmployeeID
join reg in context.Region
on reg.RegionID equals tr.RegionID
select new {
emp.FirstName,
emp.LastName,
tr.TerritoryDescription,
reg.RegionDescription
}).ToList();

Linq join count select

I have this simple code that returns a list of products but now I need to somehow fetch the same lis of products BUT i need to add a new column or value based on a view count.
var products = db.Products.Where(p => p.ProductOwnerUserId == userID).OrderByDescending(p => p.ProductID);
this is what i have so far but i am no expert in LINQ so i was wondering if someone could help me here.
This is a kind of pseudo-code of what i am looking for
var products = from p in db.Products
join pr in db.Reviews on p.ProductID equals pr.ReviewForProductID
into g select new
{
p.*,
ProductView = g.Count(a => a.ReviewForProductID)
};
i have found my OWN answer since nothing came up from you guys... but thanx for the initial tips... im quite new with linq and complexe queries can be hard to understand and fit inside existing code/view
here is my solution:
Thank you for your first answer and well just too bad for the second one that NEVER came... FYI, since my product class is a partial class already a just added another new ProductView.cs partial class containg the new Property and my query (functionnal and tested) looks like this now:
var products = (from p in db.Products
join pr in db.Reviews on p.ProductID equals pr.ReviewForProductID
into g
select new GenericEcomDataAccess.Product
{
ProductID = p.ProductID,
ProductOwnerUserId = p.ProductOwnerUserId,
ProductCurrency = p.ProductCurrency,
ProductDescription = p.ProductDescription,
ProductPrice = p.ProductPrice,
ProductImage = p.ProductImage,
ProductName = p.ProductName,
ProductCount = g.Count()
}).Where(p => p.ProductOwnerUserId == userID)
.OrderByDescending(p => p.ProductID).AsEnumerable();
var products = db.Products.Where(p => p.ProductOwnerUserId == userID)
.OrderByDescending(p => p.ProductID)
.Select(p=> new {Product = p, Count = p.Reviews.Count()});
If you have the foreign keys set up properly

translating complex T-SQL query to LINQ to Entities

This is the SQL code the produces the correct results:
select s.Code, s.Name, coalesce(ss.Url, a.Url), a.SocialMediaTypeKey
from School s
Left join
(
SELECT dbo.SchoolSocialMedia.SocialMediaTypeKey
, SchoolSocialMedia.Url
, dbo.Department.Name
, dbo.Department.ImportBusinessKey
FROM dbo.SchoolSocialMedia
INNER JOIN dbo.Department ON dbo.SchoolSocialMedia.DepartmentId = dbo.Department.Id
) A
ON 1 = 1
Left join dbo.SchoolSocialMedia ss ON ss.SchoolId = s.Id and ss.SocialMediaTypeKey = a.SocialMediaTypeKey
where s.[DeactivatedDate] is null
This is how far I have gotten in C#, but it is not producing the correct results--in fact, it is returning zero results:
var departmentSocialMediaResult =
from ssm in context.SchoolSocialMedia
from d in context.Department.Where(d => d.Id == ssm.DepartmentId)
select new { ssm.SocialMediaTypeKey,
ssm.Url,
d.Name,
ssm.SchoolId };
var result =
(from s in context.School
from ssm in context.SchoolSocialMedia.DefaultIfEmpty()
from dssm in departmentSocialMediaResult.DefaultIfEmpty()
.Where(dssm => dssm.SchoolId == s.Id && dssm.SocialMediaTypeKey == ssm.SocialMediaTypeKey)
select new { ssm.SchoolId, ssm.SocialMediaTypeKey, ssm.Url })
.ToDictionary(ssm => new SchoolSocialMediaKey(
ssm.SchoolId, ssm.SocialMediaTypeKey),
ssm => ssm.Url);
Does anyone have any suggestions on how to better convert the T-SQL to LINQ to Entities? What am I doing wrong? TIA.
UPDATE:
Thank you, #Aducci, your response is the correct answer. Since the result is being put into a dictionary, this is what I ended up using:
var query =
(from s in context.School
from a in
(
from ssm in context.SchoolSocialMedia
join d in context.Department on ssm.DepartmentId equals d.Id
select new
{
ssm.SocialMediaTypeKey,
ssm.Url,
d.Name
}
).DefaultIfEmpty()
from ss in context.SchoolSocialMedia
.Where(x => s.Id == x.SchoolId)
.Where(x => a.SocialMediaTypeKey == x.SocialMediaTypeKey)
.DefaultIfEmpty()
select new
{
ss.SchoolId,
Url = ss.Url ?? a.Url,
a.SocialMediaTypeKey
}).Distinct();
return
query
.ToDictionary(
ssm => new SchoolSocialMediaKey(
ssm.SchoolId, ssm.SocialMediaTypeKey),
ssm => ssm.Url);
I am sure there is a better way to write the original query, but instead of spending too much time analyzing I just translated it into linq. In general, your linq query should have the same structure as the tsql query like this:
var query =
from s in context.School
from a in
(
from ssm in context.SchoolSocialMedia
join d in context.Department on ssm.DepartmentId equals d.Id
select new
{
ssm.SocialMediaTypeKey,
ssm.Url,
d.Name,
d.ImportBusinessKey
}
).DefaultIfEmpty()
from ss in context.SchoolSocialMedia
.Where(x => s.Id == x.SchoolId)
.Where(x => a.SocialMediaTypeKey == x.SocialMediaTypeKey)
.DefaultIfEmpty()
select new
{
s.Code,
s.Name,
Url = ss.Url ?? a.Url,
a.SocialMediaTypeKey
};

How to convert Linq expression with multiple joins into method syntax OR retrieve select index?

I have an existing (working!) linq expression:
from ca in db.CustomAnswer
join ss in db.SurveySubmission on ca.SubmissionId equals ss.Id
join cq in db.CustomQuestion on ca.QuestionId equals cq.Id
where (ss.SurveyId == request.SurveyId)
orderby ss.Submitted, cq.SortOrder
select new
{
SubmissionId = ss.Id,
Answer = ca.Answer
}
I want to add the index of the select into the new object, e.g.
from ca in db.CustomAnswer
join ss in db.SurveySubmission on ca.SubmissionId equals ss.Id
join cq in db.CustomQuestion on ca.QuestionId equals cq.Id
where (ss.SurveyId == request.SurveyId)
orderby ss.Submitted, cq.SortOrder
select new
{
SubmissionId = ss.Id,
**Code = selectIndex,**
Answer = ca.Answer
}
To do this, I believe I need to first convert my query to method syntax so I can use the Select((q, index) => ...) form. To my simple mind, I think it should be:
db.SurveySubmission
.Where(ss => ss.SurveyId == request.SurveyId)
.OrderBy(ss => ss.Submitted)
.Join(db.CustomAnswer, ss => ss.Id, ca => ca.SubmissionId, (ss, ca) => new { ss, ca })
.Join(db.CustomQuestion, o => o.ca.QuestionId, cq => cq.Id, (o, cq) => new { o.ss, o.ca, cq })
.OrderBy(q => q.cq.SortOrder)
.Select((q, idx) => new {
SubmissionId = q.ss.Id,
Answer = q.ca.Answer,
Code = idx
});
However, when the expression is evaluated I get an error:
LINQ to Entities does not recognize the method
'System.Linq.IQueryable1[<>f__AnonymousTypef3[System.Guid,System.String,System.Int32]]
Select[<>f_AnonymousTypee3,<>f__AnonymousTypef3]
(System.Linq.IQueryable1[<>f__AnonymousTypee3[My.Data.Namespace.SurveySubmission,
My.Data.Namespace.CustomAnswer,My.Data.Namespace.CustomQuestion]],
System.Linq.Expressions.Expression1[System.Func3[<>f_AnonymousTypee3[My.Data.Namespace.SurveySubmission,
My.Data.Namespace.CustomAnswer,My.Data.Namespace.CustomQuestion],System.Int32,<>f__AnonymousTypef3[System.Guid,
System.String,System.Int32]]])'
method, and this method cannot be translated into a store expression.
I'm hoping this is glaringly obvious to someone? I've stared at it for several hours and the only conclusion I can make is that I'm not clever enough ... can anyone help please??
EF can't translate that into SQL, because in SQL sets are unordered; the idea of an index just doesn't make any sense to it.
Instead do everything but getting the index using an EF query, and then tack on the indexes in a linq to objects query:
var query = //your original query goes here
var finalQuery = query.AsEnumerable()
.Select((answer, index) => new
{
answer.SubmissionId,
answer.Answer,
Code = index,
});

Categories