Error on LINQ statement with enclosing variable - vb.net

Trying to run the following LINQ statment:
Dim jobId As Integer = CInt(payment.ForJob)
Dim currentPaid = From a In db.Payments
Where a.ForJob = jobId
Select a.Amount
Get the following error on a.Amount though:
Range variable 'Amount' hides a variable in an enclosing block or a range variable previously defined in the query expression
Function RecordPaymentForJob(payment As Payment) As ActionResult
If ModelState.IsValid Then
Dim jobId As Integer = CInt(payment.ForJob)
Dim new currentPaid = From a In db.Payments
Where a.ForJob = jobId
Select a.Amount
Dim totalPaid As Double = currentPaid.Sum()
If (totalPaid + payment.Amount) > (db.Jobs.Find(payment.ForJob).JobAmount * -1) Then
db.Jobs.Find(payment.ForJob).JobStatus = "Paid"
Else
db.Jobs.Find(payment.ForJob).JobStatus = "Part Paid"
End If
Dim Id As Integer = payment.CustomerId
Dim amount As Double = db.Customers.Find(Id).AccBalance
amount += payment.Amount
db.Customers.Find(Id).AccBalance = amount
db.Payments.Add(payment)
db.SaveChanges()
Return Redirect("/Payment/PaymentSuccessful")
End If
Return View(payment)
End Function

I suspect this is the problem:
Dim amount As Double = db.Customers.Find(Id).AccBalance
I don't know VB very well, but I suspect the scope of this variable is the scope of the whole block, including that LINQ statement. In C# at least, that wouldn't be a problem... but the Select clause in VB works somewhat differently, I believe.
One alternative would be to compute the sum directly:
Dim totalPaid = db.Payments.Where(Function(a) a.ForJob = jobId).
Sum(Function(a) a.Amount)
My VB is pretty poor, but I think that should work.

Related

how to sum values of same id in datagridview?

i am trying to sum values of same id in datagridview and trying to update sql database table. how to do it?
For i As Integer = 0 To DataGridView2.Rows.Count - 1
If Convert.ToInt32(DataGridView2.Rows(i).Cells(0).Value) = Convert.ToInt32(DataGridView2.Rows(i).Cells(0).Value) Then
y += Convert.ToInt32(DataGridView2.Rows(i).Cells(3).Value)
End If
Next
As you have been already told, the if statement you are coding is comparing a cell with itself, which doesn't make sense, because it Will always return true.
I'm guessing that you need to compare all cells that share the same id and sum the result, but you would need to elaborate the question better, so we can understand what your actuall purpose is.
you can use Dictionary to check and group id with sum values
Dim totals As Dictionary(Of String, Integer) = New Dictionary(Of String, Integer)()
For i As Integer = 0 To DataGridView2.Rows.Count - 1
Dim group As String = Convert.ToInt32(DataGridView2.Rows(i).Cells("id").Value)
Dim qty As Integer = Convert.ToInt32(DataGridView2.Rows(i).Cells("value").Value)
If totals.ContainsKey(group) = False Then
totals.Add(group, qty)
Else
totals(group) += qty
End If
Next
or use group with LINQ:
Dim totals = DataGridView2.Rows.Cast(Of DataGridViewRow)().GroupBy(Function(row) row.Cells("id").Value.ToString()).[Select](Function(g) New With {Key
.id= g.Key, Key
.SumValues = g.Sum(Function(row) Convert.ToInt32(row.Cells("value").Value))
})

Convert String to integer and get null equal to 0

May I know got any simple way to perform this? It will hit an error when a.text is null. If I don't detect one by one, With a simple code may I convert a.text null to 0?
Dim count1 As Integer = 0
count1 = Convert.ToInt32(a.Text) + Convert.ToInt32(b.Text) + Convert.ToInt32(c.Text)
txt_display.Text = count1
Got any other method rather that I do like below detect one by one.
if a.Text = "" Then
a.Text = 0
End If
You have to detect one by one. Better way, will be to create your own function. Try below.
Dim count1 As Integer = 0
count1 = ConvertToInteger(a.Text) + ConvertToInteger(b.Text) + ConvertToInteger(c.Text)
txt_display.Text = count1
Private Function ConvertToInteger(ByRef value As String) As Integer
If String.IsNullOrEmpty(value) Then
value = "0"
End If
Return Convert.ToInt32(value)
End Function
If your objective is to sum the values in your textboxes and ignore the textboxes that cannot be converted to integers then you can simply use Int32.TryParse.
It will set your variable to 0 if the text cannot be converted to an integer without throwing exceptions.
' In place of your textboxes
Dim x1 As String = "2"
Dim x2 As String = Nothing
Dim x3 As String = "5"
Dim a, b, c As Integer
Int32.TryParse(x1, a)
Int32.TryParse(x2, b)
Int32.TryParse(x3, c)
Dim result = a + b + c
Console.WriteLine(result)
Instead, if you want to write the "0" string into the textbox text to signal your user of the wrong input, then you have to check the textboxes one by one, again using Int32.TryParse
Dim value1 as Integer
if Not Int32.TryParse(a.Text, value1) Then
a.Text = "0"
End If
' Here the variable value1 contains the converted value or zero.
' repeat for the other textboxes involved
A different approach using If Operator:
Dim count1 As Integer = 0
count1 = If(String.IsNullOrEmpty(a.Text), 0, Convert.ToInt32(a.Text)) + If(String.IsNullOrEmpty(b.Text), 0, Convert.ToInt32(b.Text)) + If(String.IsNullOrEmpty(c.Text), 0, Convert.ToInt32(c.Text))
txt_display.Text = count1
Example:
If String.IsNullOrEmpty(a.Text) Then
a.Text = "0"
End If
As per the Microsoft Documentation, a null string (Nothing) is different from an empty string (""):
The default value of String is Nothing (a null reference). Note that this is not the same as the empty string (value "").
You also use the = operator, which can be tricky with String types. For more info, see this post and the answer which was awarded a 50 points bounty.
If you use If with only two arguments, the following code
If a.Text Is Nothing Then
a.Text = 0
End If
Can be turned into a one-liner: Dim MyNumber as Integer = If(a.Text, 0)
If you meant to work with empty strings, then you can use: Dim MyNumber as Integer = If(a.Text.Length = 0, 0, a.Text).
If you want to deal with both, you can use String.IsNullOrEmpty(a.Text) as suggested by the currently accepted answer; or you can use a.Text="", a.Text = String.Empty, or a.Text = vbNullString, which are all equal (see the post I referred to earlier)
Finally, note that the conversion from a String type to an Integer type is made implicitly. There is no need to use the explicit cast conversions such as CType() or Convert.ToInt32.

Fastest way to get a row using TableAdapter

From my TableAdapter SELECT statement, I do a
SELECT StudentID FROM dbo.Student WHERE Email = #Email
And in my .vb code, I call the function out and do a for each loop like this:
Dim myStudentID As Integer
Dim myTable = StudentTableAdapter1.GetStudentID("myEmail#mail.com")
For Each myRow As DataRow In myTable.Rows
myStudentID = myRow.Item("StudentID")
MessageBox.Show(myStudentID)
Next
However I wish to shorten this further. Is there a way to get the row faster?
If you're absolutely sure that you will only return a row, you can do as follows:
Dim myStudentID As Integer
Dim myTable = StudentTableAdapter1.GetStudentID("myEmail#mail.com")
myStudentID = myTable(0)("StudentID")
MessageBox.Show(myStudentID)

Access crosstab query data parameter not filtering query

I have finally got my crosstab report to dynamically update but for some reason the date parameters are not passing to either the report or the query.
I have a recordset updating the crosstab report and on hover/step through the date parameter in vba is showing the correct date but the report is still showing all data.
The query is also showing data for all dates. Is it something I have done wrong in the query? I have tried every option I could find in what seems like every forum and just can't get a solution.
This is the SQL for the query
PARAMETERS [Forms]![frm_menu]![txtFromDate] DateTime,
[Forms]![frm_menu]![txtToDate] DateTime,
[Forms]![frm_menu]![cmbMplTag1] Text ( 255 ),
[Forms]![frm_menu]![cmbMplTag2] Text ( 255 ),
[Forms]![frm_menu]![cmbMplTag3] Text ( 255 ),
[Forms]![frm_menu]![cmbMplTag4] Text ( 255 ),
[Forms]![frm_menu]![cmbMplTag5] Text ( 255 );
TRANSFORM First(tbl_logdata.Input_Value) AS FirstOfInput_Value
SELECT tbl_logdata.Log_Date, tbl_logdata.Log_Time
FROM tbl_logdata
WHERE (((tbl_logdata.Log_Date) Between [Forms]![frm_menu]![txtFromDate]
And [Forms]![frm_menu]![txtToDate])
AND ((tbl_logdata.tag)=[Forms]![frm_menu]![cmbMplTag1]))
OR (((tbl_logdata.tag)=[Forms]![frm_menu]![cmbMplTag2]))
OR (((tbl_logdata.tag)=[Forms]![frm_menu]![cmbMplTag3]))
OR (((tbl_logdata.tag)=[Forms]![frm_menu]![cmbMplTag4]))
OR (((tbl_logdata.tag)=[Forms]![frm_menu]![cmbMplTag5]))
GROUP BY tbl_logdata.Log_Date, tbl_logdata.Log_Time
PIVOT tbl_logdata.tag;
And this is the VBA for the crosstab report. The parameters for the cmbMplTag# are working fine:
Private Sub Report_Open(Cancel As Integer)
Dim rst As dao.Recordset
Dim db As dao.Database
Dim qdf As dao.QueryDef
Dim i As Integer
Dim j As Integer
Set db = CurrentDb
Set qdf = db.QueryDefs("qry_MplTagsSummary")
'on hover shows date from textbox'
qdf.Parameters("Forms!frm_menu!txtFromDate") = [Forms]![frm_menu]![txtFromDate]
'on hover shows date from textbox'
qdf.Parameters("Forms!frm_menu!txtToDate") = [Forms]![frm_menu]![txtToDate]
qdf.Parameters("[Forms]![frm_menu]![cmbMplTag1]") = [Forms]![frm_menu]![cmbMplTag1]
qdf.Parameters("[Forms]![frm_menu]![cmbMplTag2]") = [Forms]![frm_menu]![cmbMplTag2]
qdf.Parameters("[Forms]![frm_menu]![cmbMplTag3]") = [Forms]![frm_menu]![cmbMplTag3]
qdf.Parameters("[Forms]![frm_menu]![cmbMplTag4]") = [Forms]![frm_menu]![cmbMplTag4]
qdf.Parameters("[Forms]![frm_menu]![cmbMplTag5]") = [Forms]![frm_menu]![cmbMplTag5]
Set rst = qdf.OpenRecordset()
rst.MoveFirst
j = -1
i = 0
For i = 0 To rst.Fields.Count - 1
j = j + 1
Select Case j
Case 0
Me.Log_Date.ControlSource = rst.Fields(i).Name
Case 1
Me.Log_Time.ControlSource = rst.Fields(i).Name
Case 2
Me.field1.ControlSource = rst.Fields(i).Name
Case 3
Me.field2.ControlSource = rst.Fields(i).Name
Case 4
Me.Field3.ControlSource = rst.Fields(i).Name
Case 5
Me.Field4.ControlSource = rst.Fields(i).Name
Case 6
Me.Field5.ControlSource = rst.Fields(i).Name
End Select
skip_it:
Next i
rst.Close
Set rst = Nothing
End Sub
Please let me know if I have not provided enough details/information
Check your SQL WHERE clause conditional logic. As is, the logic filters records in either (not both) camps:
Falling in the date range and query's tag equals only form's tag1
Query's tag equals any of form's tag2 - tag5.
Possibly you meant to separate the date range and tags. So wrap parentheses around each condition with an AND operator, even use the IN clause. See below with indentation to illustrate:
...
WHERE (
(
(tbl_logdata.Log_Date) Between [Forms]![frm_menu]![txtFromDate]
And [Forms]![frm_menu]![txtToDate]
)
AND (
(tbl_logdata.tag) IN (
[Forms]![frm_menu]![cmbMplTag1],
[Forms]![frm_menu]![cmbMplTag2],
[Forms]![frm_menu]![cmbMplTag3],
[Forms]![frm_menu]![cmbMplTag4],
[Forms]![frm_menu]![cmbMplTag5]
)
)
)
GROUP BY tbl_logdata.Log_Date, tbl_logdata.Log_Time
You may have to convert to a true date value. And use the Value property:
qdf.Parameters("Forms!frm_menu!txtFromDate").Value = DateValue([Forms]![frm_menu]![txtFromDate])
qdf.Parameters("Forms!frm_menu!txtToDate").Value = DateValue([Forms]![frm_menu]![txtToDate])

SSRS expression - query from dataset, with group

Let's say for each student, I have a note of an exam and I need to calculate the percentile rank... of each question, each group of question and total exam (each student).
Do to that I need, for each question, group of question, and total exam:
1) x = the score (That I have of course)
2) the count of score above x
3) the count of score equal to x
4) the count total of score
Do to that it looks like I need to use sub-select for me, in a T-SQL query. Calculate everything inside a big dataset and use it.
Is there a way to acheive that inside SSRS?
I found that interesting post about the percentile function in SSRS, I will give it a try.
https://www.katieandemil.com/ssrs-percentile-function-2008-r2-calculation-custom-code-example?tab=article
I had to create another function to return the rank, but the main idea was there:
Public Shared Dim values As System.Collections.ArrayList
Public Shared Function AddValue(ByVal newValue As Decimal) As Decimal
If (values Is Nothing) Then
values = New System.Collections.ArrayList()
End If
values.Add(newValue)
AddValue = values.Count
End Function
Public Shared Function GetRankPercentile(ByVal CurrentValue As Decimal) As Decimal
Dim countTotal As Integer = values.Count 'nombre total de données
Dim countGreater As Integer = 0
Dim countEqual As Integer = 0
Dim iLoop As Integer
Dim tmpArray as system.array
tmpArray = values.ToArray()
For iLoop = LBound(tmpArray) To UBound(tmpArray)
If tmpArray(iLoop) CurrentValue Then countGreater = countGreater + 1
If tmpArray(iLoop) = CurrentValue Then countEqual = countEqual + 1
Next
GetRankPercentile = Math.Ceiling((countGreater + (countEqual / 2)) / countTotal * 5)
End Function