Linq : Nullable object must have a value - vb.net

i have this query as linq:
Dim result = (From c In query _
Where Not bannedCCList.Contains(c.num_reserv) _
Group c By c.code_operation, c.code_type _
Into nbr = Count(CInt(c.Code_bien)), acmp = Sum(CDec(c.TotalAcomp)) _
Select nbr, acmp).ToList
but i get the error:
An object that allows Null must have a value
how i can put acmp=0 if c.TotalAcomp is nothing
i that my query look like:
acmp =IIF(Sum(CDec(c.TotalAcomp)) is nothing,0, Sum(CDec(c.TotalAcomp)) _
but it doesn't work.

try this:
acmp =IIF(Sum(CDec(c.TotalAcomp)) is DBNull.Value,0, Sum(CDec(c.TotalAcomp))

Don´t use IIF. It´s old VB6 garbage, e.g. it evaluates always both sides even if the true-part returns true. Use If instead.
Your check if the variable is Nothing happens at the wrong place. You have to check it inside the Sum function not afterwards.
Also use HasValue and Value properties of nullable types.
In this case you don´t have to cast any of your expression (besides you casted to the wrong type. If your variable is of type Double don´t cast to Decimal).
The following code worked for me:
acmp = Sum(If(Not c.TotalAcomp.HasValue, 0, c.TotalAcomp.Value))

Related

Access - "Data type mismatch in criteria expression" with VBA function

I get error Data type mismatch in criteria expression when running this query.
See below what I tried. Question is how can I investigate further to find the error?
SELECT qCalls.Senso, qCalls.Data, qCalls.Ora, qCalls.NumeroPulito, qCalls.Durata, qContactsOutlookPerCallsUNION.Azienda, IIf(Count([NOME])=1,First([NOME]),"**nomi multipli**") AS Nome2
FROM qCalls INNER JOIN qContactsOutlookPerCallsUNION ON qCalls.NumeroPulito = qContactsOutlookPerCallsUNION.Numero
GROUP BY qCalls.Senso, qCalls.Data, qCalls.Ora, qCalls.NumeroPulito, qCalls.Durata, qContactsOutlookPerCallsUNION.Azienda
ORDER BY qCalls.Data DESC;
Both qCalls and qContactsOutlookPerCallsUNION run correctly when called separately.
There is no criteria expression (= WHERE clause, as I understand it) in my SQL. I then think the data type issue is on the INNER JOIN part but:
qCalls.NumeroPulito is a string, comes from: CStr(Replace([Number],"+39","")) AS NumeroPulito
qContactsOutlookPerCallsUNION.Numero is a string, it comes from: IIf(IsNull([Phone]),Null,PulisciTelPerCalls([Phone])) AS Fisso where PulisciTelPerCalls() is a VBA function which returns a string
Without being too sure, I believe the error is caused by the inline if statement IIF() since it checks both conditions anyway, thus could be sending a null value to the function.
I think you should scrap the IIF and handle null values in the function.
Public Function PulisciTelPerCalls(ByVal Phone As Variant) As String
If IsNull(Phone) Then
PulisciTelPerCalls = vbNullString
Exit Function
End If
'rest of method
End Function
Then just call the method directly:
PulisciTelPerCalls([Phone]) AS Fisso
CStr on a string doesn't make sense. Try removing it and use Nz:
Replace([Number],"+39","") AS NumeroPulito
and
PulisciTelPerCalls(Nz([Phone])) AS Fisso
or
IIf(IsNull([Phone]),"",PulisciTelPerCalls([Phone])) AS Fisso

How to concatenate date variables to create between in where condition

While I am trying to set my value to between the user given start date and end date for a query, I am running into a run-time error 3071 (The expression is typed incorrectly or it is too complex)
This is being used to pass a user given variable from a form to a query
Please see below
WHERE (
IIf([Forms]![Find]![Entity]<>"",DB.Entity=[Forms]![Find]![Entity],"*")
AND IIf([Forms]![Find]![AEPS]<>"",DB.AEPSProgram=[Forms]![Find]![AEPS],"*")
AND IIf([Forms]![Find]![DeliveryType]<>"",DB.DeliveryType=[Forms]![Find]![DeliveryType],"*")
AND IIf([Forms]![Find]![ReportingYear] is not Null,DB.ReportingYear=[Forms]![Find]![ReportingYear],"*")
AND IIf([Forms]![Find]![Price] is not Null,DB.Price=[Forms]![Find]![Price],"*")
AND IIf([Forms]![Find]![Volume]is not Null,DB.Volume=[Forms]![Find]![Volume],"*")
AND IIf([Forms]![Find]![sDate] is not Null AND [Forms]![Find]![eDate] is not Null,DB.TransactionDate= ">" & [Forms]![Find]![sdate] & " and <" & [Forms]![Find]![edate],"*")
);
If I set it equal to one of the dates it works as expected. I assume I am missing something with how I am joining the dates
Thank you
This (for the date field only) works:
WHERE (((DB.TransactionDate)>[Forms]![Find]![sdate] And (DB.TransactionDate)<[Forms]![Find]![edate])) OR ((([Forms]![Find]![sDate]+[Forms]![Find]![eDate]) Is Null));
Don't use *, it is for use with Like.
Consider assigning NULL condition to corresponding column via NZ() which sets column equal to itself and so avoids filtering any rows by that respective condition. Asterisks alone does not evaluate to a boolean condition unless using LIKE operator.
WHERE DB.Entity = NZ([Forms]![Find]![Entity], DBEntity)
AND DB.AEPSProgram = NZ([Forms]![Find]![AEPS], DB.AEPSProgram)
AND DB.DeliveryType = NZ([Forms]![Find]![DeliveryType], DB.DeliveryType)
AND DB.ReportingYear = NZ([Forms]![Find]![ReportingYear], DB.ReportingYear)
AND DB.Price = NZ([Forms]![Find]![Price], DB.Price)
AND DB.Volume = NZ([Forms]![Find]![Volume], DB.Volume)
AND DB.TransactionDate >= NZ([Forms]![Find]![sdate], DB.TransactionDate)
AND DB.TransactionDate <= NZ([Forms]![Find]![edate], DB.TransactionDate)
;

Linq to entities if in select statement

I have this linq query
Dim chiamateAperte = From statoRic In
dbVulcano.StatoRic.Where(Function(s) s.RFStato >= 11 And s.RFStato <= 13 And s.Attuale = 1 And s.RFTecnico = rfTecnico)
From richiesta In
dbVulcano.Richieste.Where(Function(r) r.IDRic = statoRic.RFRic).DefaultIfEmpty()
From cliente In
dbVulcano.Clienti.Where(Function(c) c.IDCliente = richiesta.RFCliente).DefaultIfEmpty()
Select statoRic.ID, statoRic.RFRic, statoRic.RFStato, statoRic.Attuale, richiesta.Descr, cliente.RagSociale, statoRic.DataAss, statoRic.Data, dataf = If(statoRic.DataAss.HasValue, statoRic.DataAss, statoRic.Data), statoRic.OraDalle, statoRic.OraAlle
Order By dataf Descending, statoRic.OraDalle Ascending
It's working fine but I want to add an order condition on "OraDalle" field.
OraDalle it's sort of a time field, but sadly on db it's defined as smallInt (and I cannot change it), so the format is like "800" to say "eight o'clock". This field can be null.
So instead of statoRic.OraDalle I tried this:
orad=if (statoRic.OraDalle.HasValue,statoRic.OraDalle,2359)
And then
Order By dataf Descending, orad Ascending
But it throws an ugly error: cannot cast system nullable 1 to system object of type 'system.nullable'. Only primitive types or enumeration types are supported in this context
Then I tried this:
orad=statoRic.OraDalle.GetValueOrDefault(2359)
But it also throw an error like: linq to entities does not recognize the method 'Int16 GetValueOrDefault(Int16)'
So... how can I achieve what I want? This whole mess is to get a list ordered by time, where null time values are at the bottom (and not on the top, as default). Thank you all!
Instead of if (statoRic.OraDalle.HasValue,statoRic.OraDalle,2359) use if (statoRic.OraDalle,2359)
This is the equivalent of C#´s null-coalescing-operator ??:
statoRic.OraDalle ?? 2359 which was the solution for a similar question.

Using contains in Linq query produces error

I have a pretty straight forward query that is producing this error at runtime: Only arguments that can be evaluated on the client are supported for the String.Contains method.
The query is supposed to find only the categories that have transfers assigned to them. The transfers can be listed in several categories so there is no table relationship. The Categoryidhash contains data like "7~34~25~42~47". I just realized while writing this that searching for '7' will return multiple results, "7" & '47' Etc. Thats ok i'll just change id's to all double digits. meanwhile...
How can I fix this?
Private Function GetCategoryList() As List(Of Category)
Dim lst As List(Of Category) = New List(Of Category)
Using db As New IPCDataDataContext
lst = (From c In db.Categories
From t In db.Transfers
Where t.CategoryIDhash.Contains(c.ID.ToString)
Select c).ToList()
Return lst
End Using
End Function
The exception means that Contains only accepts arguments that can be converted to fixed variable in SQL. So something like Where t.CategoryIDhash.Contains(someVariable.ToString) would be possible, because someVariable.ToString can be evaluated client-side.
I don't really understand this restriction, because in SQL it is perfectly possible to use a LIKE clause with a string that is built in the SQL statement itself. This is demonstrated by the statement that fixes your problem:
lst = (From c In db.Categories
From t In db.Transfers
Where SqlMethods.Like(t.CategoryIDhash, "%" + c.ID.ToString "%")
Select c).ToList()
This generates (and executes) SQL like
...
WHERE [t1].[CategoryIDhash] LIKE (#p0 + (CONVERT(NVarChar,[t0].[ID]))) + #p1
(where #p0 and #p1 are the % characters.
Although you could do this, I wonder if you're on the right track by using this CategoryIDhash. I think you should convert it to a FK relationship (if it's in your hands to modify the database).

Operator '=' is not defined for types 'Integer' and 'IQueryable(Of Integer)'

This is giving me a headache. I have this link query here that grabs an ID
Dim mclassID = From x In db.SchoolClasses Where x.VisitDateID = _visitdateID Select x.ClassID
And then later on I have this linq query
ViewData("Staff") = From t In db.Staffs Where t.ClassID = mclassID Select t
Any help would be much appreciated. I've tried quite a few things but to no avail. I've attempted casting, converting, Is operand, etc.
The problem is that myClassID is an anonymous IQueryable. You need to force it into another type (List is my favorite), and then pull it out of that type. So if you were to select it into a List(Of Integer) you could then extract the First() one since it would be the only. You could try something like this:
Dim myClassIDList As List(Of Integer) = New List(Of Integer)( _
From x In db.SchoolClasses Where x.VisitDateID = _visitdateID Select x.ClassID)
Dim myClassID as Integer = myClassIDList.First()
Just a guess, but would it help to wrap the right-side of the equation in parenthesis? I.e.:
ViewData("Staff") = (From t In db.Staffs Where t.ClassID = mclassID Select t)
Using the Select operator, you can have multiple results returned. If you are only expecting one result (i.e. you are selecting by a primary key), then you can use Single or SingleOrDefault (depending on whether there is guaranteed to be a result) to get just that one.
Dim mclassID = (From x In db.SchoolClasses _
Where x.VisitDateID = _visitdateID _
Select x.ClassID).SingleOrDefault()
You should change this
Dim mclassID = From x In db.SchoolClasses Where x.VisitDateID = _visitdateID Select x.ClassID
to select a single instance or the first instance, otherwise it does as its reporting, returning an IEnumerable, which causes your error later.
Or you could change your second statement to something like
ViewData("Staff") = From t In db.Staffs Where mclassID.Contains(t.ClassID) Select t
taking advantage of the mclassID as an IEnumerable of int.
You can see the errors in Output if you set appropriate options: -
Navigate VS2010 menus to Tools/Options/Projects and solutions/Build and Run/
Set MSBuild Project build output verbosity to "Detailed"
I had a similar error that wasn't showing in the Error list, but with this options setting I saw: -
error BC30452: Operator '=' is not defined for types 'System.Nullable(Of Integer)' and 'Integer'.
from this statement: -
If tqGDBChart.UserIsGroupAdmin(Userid, Groupid) = 0 Then 'User is not a group admin for this group
Easily fixed it with an intermediate variable.
Dim GroupAdminCount As Integer = tqGDBChart.UserIsGroupAdmin(Userid, Groupid)
If GroupAdminCount = 0 Then 'User is not a group admin for this group
have you tried:
ViewData("Staff") = From t In db.Staffs Where t.ClassID.equals(mclassID) Select t