error in Linq query - c#

I have following Linq:
var ownerRegistryId = 731752693037116688;
var excludeTypes = new[]
{
"CA00", "CA01", "CA03", "CA04", "CA02",
"PA00", "PA01", "PA02", "PA03", "PA04"
};
var maxStateChangeMonth = 4;
var excludeStatusId = 999;
var includeMortgage = new[] { "CL10", "CL11", "PL10", "PL11" };
var sum = (
from account in context.Accounts
from owner in account.AccountOwners
where owner.AccountOwnerRegistryId == ownerRegistryId
where !excludeTypes.Contains(account.AccountType)
where account.StateChangeDate == null ||
(account.StateChangeDate.Month - DateTime.Now.Month)
<= maxStateChangeMonth
where includeMortgage.Contains(account.AccountType) ||
account.AccountType.Contains("Mortgage")
where account.AccountStatusId != excludeStatusId
select account.MinimumInstallment)
.Sum(minimumInstallment => Math.Abs(minimumInstallment));
but I get the error:
The cast to value type 'Decimal'
failed because the materialized value
is null. Either the result type's
generic parameter or the query must
use a nullable type.
this error comes as soon as I add this:
where (includeMortgage.Contains(account.AccountType) ||
account.AccountType.Contains("Mortgage"))
If I remove this from above query, it works.
The query is translation of following SQL:
SELECT Sum(ABS([Minimum Installment])) AS SumOfMonthlyPayments FROM tblAccount
INNER JOIN tblAccountOwner ON tblAccount.[Creditor Registry ID] = tblAccountOwner.
[Creditor Registry ID] AND tblAccount.[Account No] = tblAccountOwner.[Account No]
WHERE (tblAccountOwner.[Account Owner Registry ID] = 731752693037116688)
AND (tblAccount.[Account Type] NOT IN
('CA00', 'CA01', 'CA03', 'CA04', 'CA02', 'PA00', 'PA01', 'PA02', 'PA03', 'PA04'))
AND (DATEDIFF(mm, tblAccount.[State Change Date], GETDATE()) <=
4 OR tblAccount.[State Change Date] IS NULL AND ((tblAccount.[Account Type] IN ('CL10','CL11','PL10','PL11')) OR
tblAccount.[Account Type] LIKE 'Mortgage')) AND (tblAccount.[Account Status ID] <> 999)

I'd try to rewrite the last two lines of your query like so:
var sum = (
...
select account)
.Sum(a => Math.Abs(a.MinimumInstallment));
That's how I interprete this part of the exception "...or the query must use a nullable type". By using the projection select account.MinimumInstallment you have a non-nullable type, namely decimal which is the type of account.MinimumInstallment.
Not sure though, just a guess.
Edit
The problem might actually be the final assignment var sum = .... Since you don't specify the result type explicitely the compiler will here infer the type to decimal because MinimumInstallment is decimal. The query can actually return null when the selected recordset was empty so the cast to decimal is impossible.
So, let's help the compiler to infer the result type of the query to decimal?:
var sum = (decimal?)(from ... ) ?? 0;
(Replace from ... by your original query or maybe by my modified version above.)
Edit 2
OK, the first Edit didn't work (according to comment in another question). Indeed I could reproduce the issue in a similar example. But the following worked in my example:
var sum = (
...
select account)
.Sum(a => (decimal?)Math.Abs(a.MinimumInstallment))
.GetDefaultOrValue();

Try using:
Math.Abs((decimal)(minimumInstallment.HasValue ? minimumInstallment : 0));
How about:
Math.Abs((decimal)(minimumInstallment!= null ? minimumInstallment : 0));

Related

Linq query cannot convert double to double?

I have two table:
AllPhonBills
PersonalNumbers
I want to query all records from first table where the numbers exist in PersonalNumbers table or list.
Bellow is my code:
var GetMyPersonalNumbers = db.MyPersonalNumContext.Where(i => i.EmployeeId == My_Emp_Id).Select(n => n.PersonalNumber).ToList();
var GetAllPersonalCalls = from c in db.MyAllPhoneBillContext
where GetMyPersonalNumbers.Contains(c.CALLED_NUMBER)
select c;
I get bellow error:
Argument 1: Cannot convert from 'double?' to 'double'
Can anyone tell me how to fix this error
The first argument is nullable double and it cannot be turned into double automatically.
You have to do something with nulls in the sequence of nullable types, for example:
IEnumerable<double> result =
sequence.Where(x => x.HasValue).Select(x => x.Value);
It is because in your database, you have a column of type double, but that datatype can be null. You cannot compare a nullable double to a non-nullable double. You might benefit from reading this msdn page
Either one variable in your code or a field in your DB is nullable (hence the '?'), that causes your problem.
I solved my problem by using a Join query bellow is my code:
var GetAllPersonalCalls = from c in db.MyAllPhoneBillContext
join p in db.MyPersonalNumContext on c.CALLED_NUMBER equals p.PersonalNumber
where c.CALLING_NUMBER == My_Number
where c.CALL_DATE.Year == currentYear
where c.CALL_DATE.Month == currentMonth
select new PhoneBillVM
{
CALLING_NUMBER = c.CALLING_NUMBER,
CALLED_NUMBER = c.CALLED_NUMBER,
CALL_DURATION = c.CALL_DURATION,
CustomTime = c.CALL_TIME.Hour + ":" + c.CALL_TIME.Minute + ":" + c.CALL_TIME.Second,
CALL_COST = c.CALL_COST,
CALL_DATE = c.CALL_DATE
};

Null value in the result of a left outer join linq causes error

I have linq query, that left outer join two tables. I found if a value of a field returns null,, then I will get an error message:
"The cast to value type 'System.Int32' failed because the materialized value is null. Either the result type's generic parameter or the query must use a nullable type."
I copied my linq below:
var SrvRef = from s in db.SrvHeads
join r in db.Referrants on s.svhReferrer equals r.refID into r_join
from r in r_join.DefaultIfEmpty()
where s.svhAccID == accId &&
s.svhHeadCnt == HeadId
select new
{
s.svhBalance,
r.refID
};
bool FBeenPaid = SrvRef.FirstOrDefault().svhBalance == 0M; //this causes error
How can I fix this problem?
I'm slightly surprised at the kind of error you're getting, but there are two places you need to take account of the possibility of the result being null:
Within the query, where r can be null. (If you don't want to match when there are no elements in r_join matching s, you shouldn't be using a left outer join)
In the result itself: you're using FirstOrDefault() which will return null if SrvRef is empty.
So at first glance it should probably be something like:
var query = from s in db.SrvHeads
join r in db.Referrants on s.svhReferrer equals r.refID into r_join
from r in r_join.DefaultIfEmpty()
where s.svhAccID == accId && s.svhHeadCnt == HeadId
select new
{
s.svhBalance,
refId = r == null ? 0 : r.refID // Adjust to the appropriate type of refID
};
var result = query.FirstOrDefault();
bool beenPaid = result != null && result.svhBalance == 0m;
With C# 6, you can change the bottom two lines to:
bool beenPaid = query.FirstOrDefault()?.svhBalance == 0m ?? false;
Having said that:
You're not currently using refId in the result anyway - why are you including it in the result?
Are you sure you want a left outer join at all?
Are you sure that taking the first result is really what you want? What if there are multiple results in the join?
Is there any reason you're not doing the whole thing in a query? Something like:
var paid = db.SrvHeads
.Where(s => s.svhAccID == accId && s.svhHeadCnt == HeadId)
.Any(s => db.Refererrants.Any(r => s.svhReferrer == r.refID
&& s.svhBalance == 0m);
.. but just for the precise semantics you want.
I had a similar issue.
Cause: You are using from "r" in r_join.DefaultIfEmpty(). You cannot use same alias name for left outer join.
Solution: Use different alias name if DefaultIfEmpty() cases. Eg: rEmpty
I modified the below query and its working.
var SrvRef = from s in db.SrvHeads
join r in db.Referrants on s.svhReferrer equals r.refID into r_join
from rEmpty in r_join.DefaultIfEmpty()
where s.svhAccID == accId &&
s.svhHeadCnt == HeadId
select new
{
s.svhBalance,
refID = rEmpty == null ? 0 : rEmpty.refID
};
what i think is causing an error is that svhBalance is an int32 value type and you are accessing a null value returned by SrvRef.FirstOrDefault().
please try the following line and let me know if it helped you.
if svhBalance is an int value type
var SrvRefObj= SrvRef.FirstOrDefault(); bool FBeenPaid = (((SrvRefObj!=null)&&(SrvRefObj.svhBalance
!=null))?(SrvRefObj.svhBalance == 0):(false))
else if it's a decimal value type
var SrvRefObj= SrvRef.FirstOrDefault(); bool FBeenPaid = (((SrvRefObj!=null)&&(SrvRefObj.svhBalance
!=null))?(SrvRefObj.svhBalance == 0M):(false))

Unable to create a constant value of type 'Anonymous type'

I have two linq queries. I want to use result of one query in another query.
var t2s = (from temp3 in _ent.Products
where temp3.Row_Num == 2
select new { temp3.ProductID });
Then I use this var in another query:
var _query = (from P1 in _ent.brands
join temp2 in on
new { Produ_ID = (Int32?)P1.Prod_ID }
equals new { Produ_ID = (Int32?)temp2.ProductID }
);
When I run the first query by itself it gives me the right result. If I run the second one without a join it gives me right result, but with a join gives me the following error:
error: Unable to create a constant value of type 'Anonymous type'. Only primitive types ('such as Int32, String, and Guid') are supported in this context
Are you sure you need a join? What about this:
var t2s = _ent.Products.Where(t => t.Row_Num == 1).Select(t =>t.ProductID);
var _query = _ent.brands.Where(b => t2s.Contains(b.Prod_ID));
You may need to change things slightly depending on whether ProductID and/or Prod_ID are nullable.
Try changing your queries as follows:
var t2s = from temp3 in _ent.Products
where
temp3.Row_Num == 2
select temp3.ProductID;
var _query = from P1 in _ent.brands
join temp2 in t2s on P1.Prod_ID equals temp2
select ...

Problem with LINQ to Entities query using Sum on child object property

Given this query:
from s in services
select new
{
s.Id,
s.DateTime,
Class = s.Class.Name,
s.Location,
s.Price,
HeadCount = s.Reservations.Sum(r => r.PartySize), // problem here. r.PartySize is int
s.MaxSeats
}
If the service doesn't have any reservations, this exception is thrown:
System.InvalidOperationException: The cast to value type 'Int32' failed because the materialized value is null. Either the result type's generic parameter or the query must use a nullable type.
I get it, but how should I deal with it? My intention is if there are no reservations, then HeadCount be assigned 0.
There's an even simpler solution:
from s in services
select new
{
s.Id,
s.DateTime,
Class = s.Class.Name,
s.Location,
s.Price,
HeadCount = (int?)s.Reservations.Sum(r => r.PartySize),
s.MaxSeats
}
Note the cast. This may also produce simpler SQL than #Ahmad's suggestion.
Essentially, you're just helping out type inference.
You should check for it:
HeadCount = s.Reservations != null ? s.Reservations.Sum(r => r.PartySize) : 0,
This should resolve your problem:
Try to cost the int to int?
from s in services
select new
{
s.Id,
s.DateTime,
Class = s.Class.Name,
s.Location,
s.Price,
HeadCount = s.Reservations.Sum(r => (int?) r.PartySize),
s.MaxSeats
};
HeadCount = HeadCount ?? 0;
A simple ternary operator should fix the problem nicely...
something like this:
HeadCount = (s.Reservations != null && s.Reservations.Any()) ? s.Reservations.Sum(r => r.PartySize) : 0;
This will handle for both null and empty situations

Linq to Sql Enums and Conditional Operator

Whichever way I do it, it seems something goes wrong when using the conditional operator on enum values in Linq to Sql. For example
var ret = from listings in db.Listings
select new Listing
{
ID = listings.ID,
//etc
OrderStatus = listings.OrderItems.Count > 0
? listings.OrderItems.First().Order.OrderStatus : OrderStatus.NotCheckedOut
};
System.Data.SqlClient.SqlException:
Conversion failed when converting the
nvarchar value 'Charged' to data type
int..
When I leave the enum field as nvarchar mapped to a string I get similar conversion errors. How to workaround this ?
This works, maybe there's a better way though ?
var ret = from listings in db.Listings
let ordS = listings.OrderItems.Count > 0 ?
listings.OrderItems.First().Order.OrderStatus.ToString() : OrderStatus.NotCheckedOut.ToString()
select new Listing
{
ID = listings.ID,
//etc
OrderStatus = (OrderStatus)Enum.Parse(typeof(OrderStatus), ordS)
};

Categories