How to add sql 'when' functionality in c# linq - c#

I have the following parameters:
public object GetDataByProjectCostID(string employeeid, DateTime costdate, int id = 0)
And the query:
var projectCost = (from pc in db.ProjectCosts
where pc.ProjectCostID == id
where System.Data.Entity.DbFunctions.TruncateTime(pc.CostDate) == costdate.Date
join p in db.Projects
on pc.ProjectID equals p.ProjectID
join sct in db.SubCostTypes
on pc.SubCostTypeID equals sct.SubCostTypeID
join ct in db.CostTypes
on sct.CostTypeID equals ct.CostTypeID
select new
{
p.ProjectName,
ct.CostTypeName,
ct.CostTypeID,
sct.SubCostTypeName,
pc.ProjectID,
pc.ProjectCostID,
pc.SubCostTypeID,
pc.Amount,
pc.Quantity,
pc.Note,
pc.CreatedBy,
sct.Unit,
pc.CreateDate,
pc.CostDate,
pc.ProjectCostImage
}).ToList();
Now my question is how i can add optional parameter in query.
Suppose if id not existed in request then i need to skip the where clause
where pc.ProjectCostID == id
In sql we can use when clause for that but what for in LINQ?
Thanks in advance.

try this
where (( id==0 || pc.ProjectCostID == id)
&& System.Data.Entity.DbFunctions.TruncateTime(pc.CostDate) == costdate.Date)

I use this technique in LinQ with the LinQ fluent form, you can try this:
//Make id nullable
public object GetDataByProjectCostID(string employeeid, DateTime costdate, int? id)
{
var projectCost = (from pc in db.ProjectCosts
//This expression is evaluated only if id has a value
where (!id.HasValue || pc.ProjectCostID == id)
&& System.Data.Entity.DbFunctions.TruncateTime(pc.CostDate) == costdate.Date
join p in db.Projects
on pc.ProjectID equals p.ProjectID
join sct in db.SubCostTypes
on pc.SubCostTypeID equals sct.SubCostTypeID
join ct in db.CostTypes
on sct.CostTypeID equals ct.CostTypeID
select new
{
p.ProjectName,
ct.CostTypeName,
ct.CostTypeID,
sct.SubCostTypeName,
pc.ProjectID,
pc.ProjectCostID,
pc.SubCostTypeID,
pc.Amount,
pc.Quantity,
pc.Note,
pc.CreatedBy,
sct.Unit,
pc.CreateDate,
pc.CostDate,
pc.ProjectCostImage
}).ToList();
}

Related

Why LINQ Sum() throws "System.Collections.Generic.KeyNotFoundException"?

Here I have
System.Collections.Generic.KeyNotFoundException: 'The given key 'EmptyProjectionMember' was not present in the dictionary.'
var res = (from c in _context.Check
join cp in _context.CheckProduct on c.Id equals cp.CheckId
join p in _context.Product on cp.ProductId equals p.Id
where c.Date.Date == date.Date
select (cp.Quantity * Decimal.ToDouble(p.Price))).Sum();
But when I write this, the code is working:
var res = (from c in _context.Check
join cp in _context.CheckProduct on c.Id equals cp.CheckId
join p in _context.Product on cp.ProductId equals p.Id
where c.Date.Date == date.Date
select (cp.Quantity * Decimal.ToDouble(p.Price)));
double sum = 0;
foreach(var el in res)
{
sum += el;
}
Why Sum() is not working?
Try the following:
res = (from c in _context.Check
join cp in _context.CheckProduct on c.Id equals cp.CheckId
join p in _context.Product on cp.ProductId equals p.Id
where c.Date.Date == date.Date
select (cp.Quantity * Decimal.ToDouble(p.Price)))
.DefaultIfEmpty(0)
.Sum();
Looks like there is nothing to select, so in that case, default to 0.
In the second case, you try to iterate an empty enumerable so it won't even go into the for each clause.
I was getting the same error when calling Any with an unsatisfied filter
public static bool IsBooking(this Address address)
=> address.ReferenceTypes.Any(referenceType
=> referenceType == ReferenceType.Booking
&& address.IsActive);
After first making sure that some elements exist, it is working - but it doesn't really make sense as now I'm calling Any twice
public static bool IsBooking(this Address address)
=> address.ReferenceTypes.Any()
&& address.ReferenceTypes.Any(referenceType
=> referenceType == ReferenceType.Booking
&& address.IsActive);
You need to call .ToList() before .Sum().

How to create a left join instead of inner join?

I have an SQL query which i am converting to Linq and i want to use Left Join instead of Inner Join.
I have tried DefaultIfEmpty() method but i haven't had any luck.
The Sql query:
SELECT t0.*, t1.* FROM entity AS t0
LEFT JOIN migration_logs AS t1 ON (CAST(t0.id AS CHAR) = t1.ObjectId and 'SASParty' = t1.ObjectType)
where t1.status is null || t1.Status <> '1' ORDER BY t0.id LIMIT 0, 10;
The Linq Query:
Entities
.Join(Migration_logs,
e => new { id = e.Id.ToString(), ObjectType = "SASParty" },
mlog => new { id = mlog.ObjectId, mlog.ObjectType },
(e, mlog) => new {e,mlog})
.Where(result => result.mlog.Status == null || result.mlog.Status != "1").DefaultIfEmpty().ToList()
I am using linqpad and when i execute the linq query it generates the following sql query:
SELECT t0.*
FROM entity AS t0
INNER JOIN migration_logs AS t1
ON ((CAST(t0.id AS CHAR) = t1.ObjectId) AND (#p0 = t1.ObjectType))
WHERE ((t1.Status IS NULL) OR (t1.Status <> #p1))
Some minor differences in the original query and generated sql query are there but i hope the problem statement is clear.
Any help would be appreciated.
I was able to find a solution with the linq to sql query and using into clause.
(from e in Entities
join mlog in Migration_logs
on new { id = e.Id.ToString(), ObjectType = "SASParty" }
equals new { id = mlog.ObjectId, mlog.ObjectType }
into results
from r in results.DefaultIfEmpty()
where r.Status == null || r.Status != "1"
select new
{
e
})
you want to perform the .DefaultIfEmpty() method on the quantity that you want to perform a left join onto. maybe this code snippet helps you
from e in Entities
join ml in Migration_lpgs on new { id=e.Id.ToString(), ObjectType="SASParty" } equals new { id=ml.Id.ToString(), mlog.ObjectType } into j
from e in j.DefaultIfEmpty()
where ml.Status == null || ml.Status != "1"
select e

Filtering a IQueryable with results from another table

I have an EF query which gets products from the database.
var query = (from pPrice in db.ProductPricing
join prod in db.Products on pPrice.ProductID equals prod.ProductID
join productExt in db.ProductsExt on prod.ProductID equals productExt.ProductID into pExts
from prodExt in pExts.DefaultIfEmpty()
where (includeNonPublic || pPrice.ShowOnline == 1)
&& ((eventID.HasValue && pPrice.EventID == eventID) || (!eventID.HasValue && !pPrice.EventID.HasValue))
orderby prod.DisplayOrder
select new ProductPricingInfo()
{
Product = prod,
ProductPricing = pPrice,
ProductExtension = prodExt
});
I have a table where I can specify add-on products (products which can be bought once the parent item has been bought).
My query to fetch these add-on products is
var addOnProductsQuery = (from pa in db.ProductAddons
where pa.EventID == eventID && pa.StatusID == 1
select new { ProductID = pa.ChildProductId });
Now what I am trying to do is filter on the query variable to only return products which are not in the addOnProductsQuery result.
Currently I have
var addOnProducts = addOnProductsQuery.ToList();
query = query.Where(e => !addOnProducts.Contains(e.Product.ProductID));
But there is a syntax error on the Contains(e.Product.ProductID)) statement
Argument 1: cannot convert from int to anonymous type: int ProductID
Chetan is right in the comments, you need to select the integer from the object before using Contains.
You can do it in 2 ways:
First you could just take the integer initially:
var addOnProductsQuery = (from pa in db.ProductAddons
where pa.EventID == eventID && pa.StatusID == 1
select new pa.ChildProductId);
This should give int as type so you can use Contains later with no problem.
Second, if you want to keep the addOnProductsQuery unchanged:
var addOnProducts = addOnProductsQuery.Select(a => a.ProductID).ToList();
query = query.Where(e => !addOnProducts.Contains(e.Product.ProductID));

Instead of FirstOrDefault() what do I use to get all values in group by?

How can I get all the values of SpecificationDetails_ID.By the below code I just get the first value form a group of values.What to do to get all values?
using(APM context=new APM())
{
var lstprodspc = (from s in context.M_ProductSpecifaction
//join p in context.M_SpecificationDetails on s.SpecificationDetails_ID equals p.ID
// join r in context.M_Specifications on p.Specification_ID equals r.ID
where s.Product_ID == P_ID
group s by s.Parent_ID into pg
select new
{
ProductSD_ID = pg.FirstOrDefault().SpecificationDetails_ID
}).ToList();
}
From the above code I just get 34,31,31,31,26,26,26,26.
You can project it using Select like this:-
select new
{
Parent_ID = pg.Key,
ProductSD_ID = pg.Select(x => x.SpecificationDetails_ID).ToList()
}).ToList();

Convert stored procedure to LINQ

I'm using MVC3 and still learning LINQ. I'm having some trouble trying to convert a query to LINQ to Entities. I want to return an Json method
My stored procedure
Create Procedure [dbo].[ResourceReports]
(
#EmployeeID int
)
as
begin
select p.projectName AS Projects, count( b.[CreatedByID]) AS Bugs
from [EmployeeDetails] e inner join [Bugs] b on e.[EmployeId] = b.[CreatedByID]
inner join Projects p on b.ProjectId = p.ProjectId
where e.[EmployeId] = #EmployeeID
group by P.projectName
end
What I have is a few tables, I started writing this out in LINQ but I'm not sure how to properly return the correct type or cast this.
My controller
public JsonResult Getchart()
{
var Bug = db.Bugs.ToList<Bug>();
var EmployeDetails = db.EmployeeDetails.ToList<EmployeeDetail>();
var projects = db.Projects.ToList<Project>();
var result = (from e in EmployeDetails
join b in Bug on e.EmployeId equals b.CreatedByID
join p in projects on b.ProjectId equals p.ProjectId
where e.EmployeId = #EmployeId
group p.projectName
select new (p.projectName as Project ,count(b.CreatedByID) as Bug)).Take(50);
return Json(result,JsonRequestBehavior.AllowGet);
}
How will I pass the parameter to for the query, want the data to be returned in json format.
Assuming you can pass the value in as a parameter to the method:
public JsonResult Getchart(int employeeId)
{
var Bug = db.Bugs.ToList<Bug>();
var EmployeeDetails = db.EmployeeDetails.ToList<EmployeeDetail>();
var projects = db.Projects.ToList<Project>();
var result = (from e in EmployeeDetails
join b in Bug on e.EmployeeId equals b.CreatedByID
join p in projects on b.ProjectId equals p.ProjectId
where e.EmployeeId == employeeId // <-- use the parameter here
group p by p.projectName into g
select new {
Project = g.Key,
Bug = g.Count()
}
).Take(50);
return Json(result,JsonRequestBehavior.AllowGet);
}
BTW I intentionally corrected a few spellings of Employee
If this is a controller action, you would probably want to pass the ID via the URL. Also, there is no need to call ToList on your tables before querying, do the query at the database and only pull down the results e.g.
public JsonResult GetChart(int employeeId)
{
var query = (from e in db.EmployeeDetails
join b in db.Bugs on e.EmployeeId equals b.CreatedById
join p in db.Projects on b.ProjectId equals p.ProjectId
where e.EmployeeId == employeeId
group new {p, b} by new {
p.ProjectName
} into g
select new {
Project = g.Key.Name,
Bugs = g.Count()
}).Take(50);
return Json(query.ToList(), JsonRequestBehaviour.AllowGet);
}
Is this what you need:
public JsonResult Getchart(int employeId)
{
var Bug = db.Bugs.ToList<Bug>();
var EmployeDetails = db.EmployeeDetails.ToList<EmployeeDetail>();
var projects = db.Projects.ToList<Project>();
var result = (from e in EmployeDetails
join b in Bug on e.EmployeId equals b.CreatedByID
join p in projects on b.ProjectId equals p.ProjectId
where e.EmployeId == employeeId
group p.projectName
select new (p.projectName as Project ,count(b.CreatedByID) as Bug)).Take(50);
return Json(result,JsonRequestBehavior.AllowGet);
}
Are you sure you want to do all of those "ToList<>()" calls? Once you call "ToList<>()", you bring all three of those tables into memory from the database. If they are large, that could be a performance issue.
public JsonResult GetChart()
{
//int employeeId
var Bug = db.Bugs.ToList<Bug>();
var EmployeDetails = db.EmployeeDetails.ToList<EmployeeDetail>();
var projects = db.Projects.ToList<Project>();
var query = (from e in EmployeDetails
join b in Bug on e.EmployeId equals b.CreatedByID
join p in projects on b.ProjectId equals p.ProjectId
where e.EmployeId == 1
group new { p, b } by new
{
p.projectName
} into g
select new ChartModel
{
ProjectName = g.Key.projectName,
bug = g.Count()
}).ToList();
return Json(query, JsonRequestBehavior.AllowGet);
}
i Got ...

Categories

Resources