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

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().

Related

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

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();
}

Linq2Sql join by multiple columns (by OR operator)?

Mow I can translate this:
SELECT *
FROM vectors as v
INNER JOIN points as p
ON v.beginId = p.id OR v.endId = p.id
Into linq2sql statement? Basically I want this:
var query = from v in dc.vectors
join p in dc.points on p.id in (v.beginId, v.endId)
...
select ...;
I know, I can do this dirty through Union construction, but is there a better way than duplicating most of the query?
You can't have an on clause in linq-to-sql with an or. You need to do:
var result = from v in dc.vectors
from p in dc.points
where p.id == v.beginId || p.id == v.endId
select new { v, p };
Equivalent to the sql of:
SELECT *
FROM vectors as v,
points as p
WHERE v.beginId = p.id
OR v.endId = p.id

Converting SQL to LINQ using MAX

I have two tables
1) T_EJV_CREDIT_DS_INDEX
2) T_EJV_CREDIT_DS_INDEX_CONTRACT
I would like a SQL query like below as a LINQ expression
SELECT MAX(INDEX_FAMILY_VERSION) FROM T_EJV_CREDIT_DS_INDEX cdi
INNER JOIN T_EJV_CREDIT_DS_INDEX_CONTRACT cdic
ON cdic.INDEX_ID = cdi.INDEX_ID
WHERE cdi.INDEX_SHORT_NAME LIKE '%#VARIABLE1%'
AND cdic.TENOR = #VARIABLE2
This is what I have attempted so far
var maxFamilyVersion = (from ic in dsIndexContract
join i in dsIndex on i.INDEX_ID equals ic.INDEX_ID
where i.INDEX_SHORT_NAME.CONTAINS(strindex) && ic.TENOR equals d.TERM
select new
{
ic.INDEX_FAMILY_VERSION.Max()
}).Take(1).ToList();
But the above mentioned starts showing compile issues with the syantax as shown below
Checking for equality in your where condition can be done with ==. The keyword equals is only used in a join condition.
var result = (from ic in dsIndexContract
join i in dsIndex on i.INDEX_ID equals ic.INDEX_ID
where i.INDEX_SHORT_NAME.CONTAINS(strindex) && ic.TENOR == d.TERM
select new
{
ic.INDEX_FAMILY_VERSION.Max()
}).FirstOrDefault();
And instead of .Take(1).ToList(), you can use .FirstOrDefault() to retrieve the first item.
Or a more efficient way is to use .Max() directly instead of .FirstOrDefault():
var result = (from ic in dsIndexContract
join i in dsIndex on i.INDEX_ID equals ic.INDEX_ID
where i.INDEX_SHORT_NAME.CONTAINS(strindex) && ic.TENOR == d.TERM
select ic.INDEX_FAMILY_VERSION).Max();
This should do it:
var maxFamilyVersion =
(from ic in dsIndexContract
join i in dsIndex on ic.INDEX_ID equals i.INDEX_ID
where i.INDEX_SHORT_NAME.CONTAINS(strindex) && ic.TENOR == d.TERM
select ic.INDEX_FAMILY_VERSION).Max();

LINQ Left Join 3 tables with OR operator

I have this SQL query:
SELECT * FROM [CMS_MVC_PREPROD].[dbo].[T_MEMBER] m
left outer join [CMS_MVC_PREPROD].[dbo].[T_COMPANY] c
ON m.Company_Id = c.Id
left outer join [CMS_MVC_PREPROD].[dbo].[T_ADRESSE] a
ON m.Id = a.Member_Id OR a.Company_Id = c.Id
But i could not translate it to Linq
I have some trouble with this line in particular:
ON m.Id = a.Member_Id OR a.Company_Id = c.Id
EDIT: I try this query from Ehsan Sajjad
from m in db.Member
join c in db.T_Company on m.Company_Id equals c.Id into a
from c in a.DefaultIfEmpty()
from ta in db.T_Address
where m.Id == ta.Member_Id || ta.Company_Id == c.Id
But it only returns members who have an address and i want all members. Maybe it will work with a full join
Thanks in advance
LINQ only supports equi-joins directly. You'll have to use a different query pattern:
from m in db.MEMBER
//add join to "c" here
from a in (
from a db.ADRESSE
where m.Id == a.Member_Id || a.Company_Id == c.Id
select a).DefaultIfEmpty()
select new { m, a }
Just a sketch. The trick is using DefaultIfEmpty on a subquery. Both L2S and EF can translate this to an OUTER APPLY which is equivalent to a LEFT JOIN.
You can write this way to make it work:
from m in db.Member
join c in db.T_Company on m.Company_Id equals c.Id into a
from c in a.DefaultIfEmpty()
from ta in db.T_Address
where m.Id == ta.Member_Id || ta.Company_Id == c.Id

How do I build up a LINQ => SQL / entities query (with joins) step-by-step?

I have the following two LINQ queries:
public int getJobsCount()
{
var numJobs =
(from j in dbConnection.jobs
join i in dbConnection.industries on j.industryId equals i.id
join c in dbConnection.cities on j.cityId equals c.id
join s in dbConnection.states on j.stateId equals s.id
join pt in dbConnection.positionTypes on j.positionTypeId equals pt.id
select j).Count();
return numJobs;
}
public List<Job> getJobs()
{
var jobs =
(
from j in dbConnection.jobs
join i in dbConnection.industries on j.industryId equals i.id
join c in dbConnection.cities on j.cityId equals c.id
join s in dbConnection.states on j.stateId equals s.id
join pt in dbConnection.positionTypes on j.positionTypeId equals pt.id
orderby j.issueDatetime descending
select new Job { x = j.field, y = c.field, etc }
).Skip(startJob - 1).Take(numJobs);
return jobs;
}
There's a lot of duplicate code in there - the "from", and "join" lines are identical, and I'll be adding in some "where" lines as well that will also be identical.
I tried adding a method that returned an IQueryable for the first part:
public IQueryable getJobsQuery()
{
var q =
from j in dbConnection.jobs
join i in dbConnection.industries on j.industryId equals i.id
join c in dbConnection.cities on j.cityId equals c.id
join s in dbConnection.states on j.stateId equals s.id
join pt in dbConnection.positionTypes on j.positionTypeId equals pt.id;
return q;
}
...but I get "a query body must end with a select clause or a group clause".
If I add a select clause on to the end off that function, I can't call count() on the result:
// getJobsQuery:
var q = from j in dbConnection.jobs
join i in dbConnection.industries on j.industryId equals i.id
join c in dbConnection.cities on j.cityId equals c.id
join s in dbConnection.states on j.stateId equals s.id
join pt in dbConnection.positionTypes on j.positionTypeId equals pt.id
select new { a = j.y, b = c.z }
// another method:
var q = getJobsQuery();
var numJobs = q.Count(); // "IQueryable doesn't contain a definition for count"
Is there a way to build up this query step-by-step to avoid duplicating a whole lot of code?
There are two ways of writing LINQ-queries, and though it doesn't really matter witch one you use it's good to know both of them cause they might learn you something about how LINQ works.
For instance, you have a set of jobs. If you were to select all jobs with an industryId of 5 (wild guess of data-types) you'd probably write something like this:
from j in dbConnection.jobs
where j.inustryId == 5
select j;
The very same query can also be written like this
dbConnections.jobs.Where(j => j.industryId == 5);
Now, I'm not here to preach saying one way is better than the other, but here you can clearly see how LINQ using the extension-methods syntax automatically selects on the iterated object (unless you do a select), whereas in the query-syntax you must do this explicitly. Also, if you were to add inn another where clause here it would look something like this:
from j in dbConnection.jobs
where j.inustryId == 5 // not using && here just to prove a point
where j.cityId == 3 // I THINK this is valid syntax, I don't really use the query-syntax in linq
select j;
While in the extension-methods you can just append more method-calls like so:
dbConnections.jobs.Where(j => j.industryId == 5)
.Where(j => j.cityId == 3);
Now this is good to know cause this means you can just put your linq-query inside a function an continue querying it. And all you need to do to make it work in your case is just explicitly select the starting variable j, or all the variables you need like so:
var q =
from j in dbConnection.jobs
join i in dbConnection.industries on j.industryId equals i.id
join c in dbConnection.cities on j.cityId equals c.id
join s in dbConnection.states on j.stateId equals s.id
join pt in dbConnection.positionTypes on j.positionTypeId equals pt.id;
select new {j = j, i = i, c = c, s = s, pt = pt };
return q;
Then you should be able to do for instance this:
getJobsQuery().Where(a => a.i.id == 5); // I used a as a name for "all", like the collection of variables
or using the query-syntax
from a in getJobsQuery()
where a.i.id == 5
select a;
Would this be better solved by returning a set of data (e.g. the common data) and querying for a subset of that data?
E.g. [pseudocode]
var allJobs =
(from j in dbConnection.jobs
join i in dbConnection.industries on j.industryId equals i.id
join c in dbConnection.cities on j.cityId equals c.id
join s in dbConnection.states on j.stateId equals s.id
join pt in dbConnection.positionTypes on j.positionTypeId equals pt.id
select j);
var myJobs = allJobs.OrderBy(j => j.issuedate).skip(expr).Take(allJobs.Count);
or similar...

Categories

Resources