List(Of <custom class>) Seems to Reset Itself - asp.net

Code:
I have a class, Pricing.vb, that accepts an IEnumerable(Of tblAccount) in its new method, where tblAccount is an Entity Framework class with an added partial class that adds non-mapped properties.
Pricing.vb:
Public Property accounts As IEnumerable(Of tblAccount)
Public Sub New(ByVal accts As IEnumerable(Of tblAccount))
Me.accounts = accts
End Sub
tblAccount.vb:
Partial Public Class tblAccount
<NotMapped>
Public Property irr As Double
End Class
The Pricing.vb class then has a method, CalcBalance:
Public Sub CalcBalance(reqPrice As Double)
Dim acctsByIRR As List(Of Long)
Dim i As Long = 0
Me.FillCashFlows(reqPrice)
Me.FillMetrics()
acctsByIRR = Me.accounts.OrderBy(Function(t) t.irr).Select(Function(t) t.acct_id).ToList()
'do ... while that removes accounts 1 by 1 by lowest ray until it is above min
Do While Me.netIRR < Me.minimumIRR
Me.accounts = Me.accounts.Where(Function(t) t.acct_id <> acctsByIRR(i))
i = i + 1
If Me.accounts.Count = 0 Then Exit Sub
Me.FillCashFlows(reqPrice)
Me.FillMetrics()
Loop
End Sub
Basically, the CalcBalance() method is designed to remove tblAccount objects one-by-one from its property Me.Accounts, in order of lowest IRR, until the IRR of the remaining accounts (Me.netIRR) meets a minimum criteria (Me.minimumIRR). The Me.netIRR property is calculated by methods FillCashFlows() and FillMetrics().
Problem:
The problem that I'm seeing, though, is that Me.accounts essentially resets itself each time the do while...loop loops. So if I have tblAccounts with acct_ids 1 through 5, and let's say that the order of lowest IRRs is 1, 2, 3, 4, and 5, then the first time the method loops it will properly remove acct_id=1 from Me.accounts. BUT, the next time it loops, acct_id=1 will reappear in Me.accounts, and it will remove acct_id=2. It will continue this weird process until of course it hits an index out of range exception.
For a little visualization, here's what the IEnumerable(Of tblAccount) looks like, by acct_id after each loop:
After 1st loop:
2
3
4
5
After 2nd loop:
1
3
4
5
After 3rd loop:
1
2
4
5
After 4th loop:
1
2
3
5
After 5th loop:
1
2
3
4
It should look like this:
After 1st loop:
2
3
4
5
After 2nd loop:
3
4
5
After 3rd loop:
4
5
After 4th loop:
5
After 5th loop:
empty, and Exit Sub

It's because you're using IEnumerable<T> and not List<T>. LINQ query is lazy loaded, so your accounts property stores the query information (how to get the results) not a list of accounts. In every iteration of Do/While you just change the definition, and later on it's called against initial data source over and over again.
Make sure to call ToList whenever you assign to accounts:
Public Sub New(ByVal accts As IEnumerable(Of tblAccount))
Me.accounts = accts.ToList()
End Sub
and
Public Sub CalcBalance(reqPrice As Double)
Dim acctsByIRR As List(Of Long)
Dim i As Long = 0
Me.FillCashFlows(reqPrice)
Me.FillMetrics()
acctsByIRR = Me.accounts.OrderBy(Function(t) t.irr).Select(Function(t) t.acct_id).ToList()
'do ... while that removes accounts 1 by 1 by lowest ray until it is above min
Do While Me.netIRR < Me.minimumIRR
Me.accounts = Me.accounts.Where(Function(t) t.acct_id <> acctsByIRR(i)).ToList()
i = i + 1
If Me.accounts.Count = 0 Then Exit Sub
Me.FillCashFlows(reqPrice)
Me.FillMetrics()
Loop
End Sub

Related

User Form multi-selection Listbox arrays or entirerow.copy?

Amateur her so bear with me. I am trying to compile VBA code which runs a userform with list box populated with a 9 column and 100 row table from worksheet1. The user selects the only the items in the list box he needs for a report and they are to copied to worksheet 2.
With help from a 6 year old post on this site, I have managed to do this using an array and a public function to select the chosen rows and then output them to worksheets2. As follows:
Private Sub CommandButton1_Click()
Dim SelectedItems() As Variant
Dim i As Integer
Dim emptyrow As Integer
wsTarget.Activate
Range("A1").Select
SelectedItems = GetSelectedRisks(RiskList)
emptyrow = 15
For i = LBound(SelectedItems) To UBound(SelectedItems)
wsTarget.Cells(emptyrow, 2).Value = SelectedItems(i)
emptyrow = emptyrow + 1
Next
End Sub
Public Function GetSelectedRisks(lBox As MSForms.ListBox) As Variant
Dim tmpArray() As Variant
Dim i As Integer
Dim SelectionCounter As Integer
SelectionCounter = -1
For i = 0 To lBox.ListCount - 1
If lBox.Selected(i) = True Then
SelectionCounter = SelectionCounter + 1
ReDim Preserve tmpArray(SelectionCounter)
tmpArray(SelectionCounter) = lBox.List(i)
End If
Next
However I can only work out how to do this for the 1st column. I just can't work out how to get the other columns into the array and then back out again.
Should I be using an array or am I making this to complicated i.e. should I just be using loops and if selected, entirerow.copy type stuff?

Checking content of textbox vb.net

I am using a text box for input to my SQL query. Based on the input I create a certain query and display the data in a gridview.
However I wish to make an adjustment for my users.
They often make an input like PL26... However this is not a valid name in the database to search for. Therefore I want to CHECK their input, and alter it accordingly, so they don't have to think about it.
I happen to know that when they type PL26 the correct input would be PL000026 ... The entity to search for is always "PL" + 6 characters/numbers... so if they wrote PL155, the number/string I pass to the sql query should become PL + 000 + 155 = PL000155.
I hope someone can help me how to accomplish this. That is if it is possible?
My idea/Pseudo code would be something like
If tbInput.txt's FIRST 2 CHARS are PL, then check total length of string
if StringLength < 8 characters, then
if length = 2 then ADD 4 0' after PL...
if length = 3 then add 3 0's after PL...
if length = 3 then add 3 0's after PL..
etc
....
...
Here we go:
Private Sub Button21_Click(sender As System.Object, e As System.EventArgs) Handles Button21.Click
Debug.Print(formatCode("PL1"))
Debug.Print(formatCode("PL"))
Debug.Print(formatCode("PL01"))
Debug.Print(formatCode("PL155"))
End Sub
Private Function formatCode(userInput As String) As String
Dim returnVal As String
If userInput.Length < 8 Then
returnVal = String.Concat(userInput.Substring(0, 2), userInput.Substring(2, userInput.Length - 2).PadLeft(6, "0"))
Else
returnVal = userInput
End If
Return returnVal
End Function
You may need to add some validation ensuring it starts with PL etc.
The following will work as long as there are no other non-numeric characters in between the PL and the numbers. You can always add it in your validation.
Dim newInput As String
If (input.StartsWith("PL")) Then
input = input.Remove(0, 2)
End If
' If this fails then it means the input was not valid
Dim numberPart = Convert.ToInt32(input)
newInput = "PL" + numberPart.ToString("D6")
Exctract a number by removing prefix "PL"
Parse to Integer
Use Custom Numeric Format Strings(zero placeholder) for adding zeros and prefix
Const PREFIX As String = "PL"
Dim exctractedNumber As Int32
If Int32.TryParse(tbInput.txt.Replace(PREFIX, String.Empty), exctractedNumber) = False Then
'Error nahdling
Exit Sub
End If
Dim finalFormat As String = String.Format("'{0}'000000", PREFIX)
Dim finalValue As String = exctractedNumber.ToString(finalFormat)
I would make use of the handy PadLeft method:
Dim input As String = "PL26"
Dim number As String = input.Substring(2, input.Length - 2)
If number.Length <> 6 Then
number = number.PadLeft(6, "0"C)
End If
MSDN String.PadLeft

How to print a list of dates asp.net

I'm trying to print a list of dates using a for loop. I'm getting an error saying 'AddDays' is not a member of 'System.Array'.
Dim payDates(10) as Date
For index As Integer = 1 to 10
Redim Preserve payDates(index)
payDates(index) = payDates.AddDays(1)
index +=1
NEXT
Response.Write(payDates)
I'm no vb expert, but you need to access the index of the array, not the array itself:
Dim payDates(10) as Date
For index As Integer = 1 to 10
Redim Preserve payDates(index)
payDates(index) = payDates(index).AddDays(1)
index +=1
NEXT
Response.Write(payDates)
Also you migzht want to write every date. In this case change you code to this:
Dim payDates(10) as Date
For index As Integer = 1 to 10
Redim Preserve payDates(index)
payDates(index) = payDates(index).AddDays(1)
Response.Write(payDates(index))
index +=1
NEXT
In essence:
payDates is of type System.Array
payDates(index) contains a DateTime variable at the position index, where index is of type int
Well, AddDays isn't a member of System.Array. But you're trying to call it anyway:
payDates.AddDays(1)
If you're trying to get a modified date, reference the date element of the array. Something like this:
payDates(index).AddDays(1)
(Note that if you're looking to display this information on a web page, it's a lot better to set the information on elements of that page than to use Response.Write(). You have very little control over where Response.Write() emits its output in the resulting page.)

Dynamically count of similar kind of Data

I have one data table in VB page which contain bulk data.In that data table one column named as vType and values in that column is one of Pr defined values such as 'A','B','C','D' etc , which comes from one Datable.
Now I want count of each type at the end.
For ex : CountA = 20,CountB=25 and so on .
Till now I have compared Each value using If condition which is static
For each dr as dataRow in dsType.rows
If dr("vType") = 'A' Then
CountA += 1
ElseIf dr("vType") = 'B' Then
CountB +=1
Next dr
and this If condition will repeat depend upon no of types in that data table (at max 8 fix values) I want to do this in single if condition ( Dynamic if Possible) Can I Count these values and store the same into single varaible? appreciate for you prompt reply.
You can use Linq-To-DataSet and Enumerable.GroupBy + Enumerable.Count on each group:
Dim typeGroups = dsType.AsEnumerable().
GroupBy(Function(row) row.Field(Of String)("vType")).
Select(Function(g) New With{ .Type = g.Key, .Count = g.Count(), .TypeGroup = g })
Note that New With creates an anonymous type in VB.NET with custom properties. So like a class on-the-fly which you can use in the current method.
Now you can enumerate the query with For Each:
For Each typeGroup In typeGroups
Console.WriteLine("Type:{0} Count:{1}", typeGroup.Type, typeGroup.Count)
Next
I cannot use Linq, i need to use simple vb only
Then use a Dictionary:
Dim typeCounts = New Dictionary(Of String, Integer)
For Each row As DataRow In dsType.Rows
Dim type = row.Field(Of String)("vType")
If (typeCounts.ContainsKey(type)) Then
typeCounts(type) += 1
Else
typeCounts.Add(type, 1)
End If
Next
Now you have a dictionary where the key is the type and the value is the count of the rows with this type.
why not getting the pretend result from the db itself?
Like so:
select count(*), vType
from someTable
group by vType
Not so sure about your question .. but this is what I've considered ..
You can make it as Sub ..
Sub AssignIncr(ByVal ds as DataSet,byval sFi as String,byval sCrit as String,ByRef Counter as Integer)
For each dr as dataRow in ds.rows
If dr(sFi) = sCrit Then Counter += 1
Next dr
End Sub
So you may use it by ..
AssignIncr(dsType,"vType","A",CountA)

Add values to dropdown list programatically at run time

I am trying to change the list item values of a dropdown list based on values of an other dropdown list. The list values of drpAdult range from 0-9 and list values of drpInfant range from 0-(Value of drpAdult selected).
So, for example, if I select 5 in the drpAdult dropdown, the range of list item values of drpInfant will be from 0-5.
I have written the code below, but it is not populating the values in the drpInfant dropdown, which I am trying to insert on drpAdult_SelectedIndexChanged event.
Protected Sub drpAdult_SelectedIndexChanged(ByVal sender As Object,
ByVal e As EventArgs) Handles drpAdult.SelectedIndexChanged
Dim count As Integer
count = drpAdult.Items.Count
Dim i As Integer
i = 0
While count > 0
i = i + 1
drpInfant.Items.Add(New ListItem(i, i))
count = count - 1
End While
End Sub
What might cause this problem, and how can I resolve it?
Not sure what "is not working" means, but this seems to be easier anyway:
Dim newCount = drpAdult.Items.Count + 1
For i As Int32 = 0 To newCount
Dim newItem As New ListItem(i.ToString, i.ToString)
drpInfant.Items.Add(newItem)
Next
You can try this. I have tested this & working fine:
Protected Sub drpAdult_SelectedIndexChanged(sender As Object, e As EventArgs)
drpInfant.Items.Clear()
Dim count As Integer = drpAdult.SelectedIndex
Dim i As Integer = 0
While count >= 0
drpInfant.Items.Add(New ListItem(i.ToString(), i.ToString()))
i = i + 1
count = count - 1
End While
End Sub
Something along these lines...
drpInfant.Items.Clear()
dim n as Integer
Integer.TryParse(drpAdult.SelectedValue, n)
For i as integer = 1 to n
if n < i Then Exit For 'it's not fun when this condition happens in VB
drpInfant.Items.Add(New ListItem(i, i))
Next

Resources