VB.Net and handling dates within Grid Controls - better way? - vb.net

While I have my app running, I question the methodology, and wondering if there’s a “better way”…
Overall design is to allow editing 200-300 records from a gridview (phase1) using VB.Net. The database itself is on SQL Server. There are a number of columns a user will enter into an “application”, and there are several columns that will be edited/maintained by “office users”, if you will. There are several dates involved in this ongoing maintenance, and that’s where the first of my questions revolves.
I have found “solutions” on the internet that got the code working, but am questioning them…
Problem #1 I ran into – dates are NULL in the database, and in trying to read them in using a SqlDataReader led to errors (cannot assign NULL to a Date object). Ok, that led into using a ternary operator to use “IsDBNull”, and either assign the value read from the DB, or to assign DateTime.MinValue. Problem “solved”…
Problem #2 – using the above method now shows dates that are the minimum VB date value – showing actual dates in the fields the user is to edit – definitely not “user friendly”, nor what I want. The only solution to this issue was:
Convert dates from Date or DateTime objects into String objects. This would then allow me to be able to assign an empty string to the gridview in the case where the date was originally NULL in the DB, which had to be transformed into DateTime.MinValue (which could be tested), and then another ternary operator to assign either “ToString” conversion, or an empty string to the gridview field.
Ok – editing is now accomplished. I added some “ScriptManager.RegisterStartupScript” commands to allow testing the validity of the dates the user enters – all is well.
Problem #3 (or 4) – I now need to update the database with the data the user entered – PRESERVING THE EMPTY DATE STRINGS – and update the database (using parameters…) with NULLs back in those date columns. However, again – the date is a string, and is empty, so I had to assign to a “MinValue”, first, then another ternary operator to test each date against “MinValue”, and either assign the date, or a DBNull.Value…
Yes, I guess I could have come up with a number of different update strings (including dates in some, excluding in others), depending on whether or not a string/date was empty or not... But that will only lead to future bugs, so, I guess I’ll be keeping a series of ternary operators.
So, the code for beginning the edit process looks something like:
While sdr.Read
Dim _date1 As Date = If(IsDBNull(sdr("date1")), DateTime.MinValue, sdr("date1"))
.
.
.
‘ Now add them to a List of my Class:
appsList.Add(New AppClass(… _
If(_date1 = DateTime.MinValue, " ", _date1.ToString("MM/dd/yyyy")), _
… )
Now to get the data back from the gridview to update the database:
Dim _date1 As Date
' see if we can convert the various dates...
Try
' see if empty…
If ((CType((row.Cells(19).Controls(0)), TextBox)).Text).Length < 2 Then
_date1 = DateTime.MinValue
Else
_date1 = DateTime.Parse((CType((row.Cells(19).Controls(0)), TextBox)).Text)
End If
Catch ex As Exception
ErrFlag = True
ScriptManager.RegisterStartupScript(Me, Page.GetType, "Script", "alert(‘Date1 Date is not valid - enter as MM/DD/YYYY');", True)
End Try
.
.
.
Dim sql As String = "UPDATE [foo_bar].[dbo].[bar_foo] set date1=#Date1, …….)
cmd.Parameters.AddWithValue("#Date1", If(_date1 = DateTime.MinValue, DBNull.Value, _date1))
Honestly, all this conversion back and forth seems like it’s going to lead to bugs or errors at some point.
So – is this the “best” method for handling this? There isn’t a cleaner way?

If your using winforms then you can handle the Format and parse of the databindings. I haven't tried it on a Gridviewtextbox but worst case you can use a custom cell template and a textbox with format and parse handlers. The code would be something like this:
mybinding = New Binding("text", DataSet1, "table1.datefield")
Me.DataGridTextBoxColumn1.TextBox.DataBindings.Add(mybinding)
AddHandler mybinding.Parse, AddressOf StringToDateTime
AddHandler mybinding.Format, AddressOf formatdate
Private Sub StringToDateTime(ByVal sender As Object, ByVal cevent As ConvertEventArgs)
If cevent.Value.GetType().Equals(GetType(String)) And _
cevent.DesiredType Is GetType(DateTime) Then
If cevent.Value <> "" Then
' Make sure matches format in format funtion
cevent.Value = DateTime.Parse(String.Format(cevent.Value, "MMM d, yy"))
Else
cevent.Value = DBNull.Value
End If
'cevent.Value = DateTime.Parse(String.Format(cevent.Value, "MMM d yyyy")
End If
End Sub
Public Sub formatdate(ByVal sender As Object, ByVal e As ConvertEventArgs)
If e.Value.GetType().Equals(GetType(DateTime)) And e.DesiredType Is GetType(String) Then
' Hard-coded or user-specified
' Make sure matches format in parse funtion
e.Value = Format(e.Value, "d")
End If
End Sub

Related

Kofax Transformation VBA Script to update field value

Im not really used on Kofax technologies and I have a Kofax Transformation form with fields on 2 different tabs. Here is an abstract of this form on which I have to interact on validation process.
Among those fields, I try to update the content of some of them with a validation rule on validation stage. I simply created a multi field validation rule and mapped correctly the fields.
It was proposed a basic script to check if the fields are valid or not. Based on this script I tried some logic. The Objective is to set the content of a field (which is empty and required) based on a basic condition on the second field.
My objective (later) will be to fill / update the fields based on the “Siret” field value with a database call.
My validation rule is the following : I check the “Siret” string length (it should be a 14 chars string). If this is true, I set the Validation to true and set the other field a value.
Private Sub Validation_Validate(ByVal ValItems As CASCADELib.CscXDocValidationItems, ByVal pXDoc As CASCADELib.CscXDocument, ByRef ErrDescription As String, ByRef ValidField As Boolean)
Dim strNAF As String
Dim strSiret As String
strNAF = ValItems.Item("NAF").Text
strSiret = ValItems.Item("Siret").Text
' enter your own validation rule here
If Len(strSiret) <= 14 Then
pXDoc.Fields.ItemByName("NAF").Text = "GOOD JOB"
ValidField = True
Else
ValidField = False
ErrDescription = "Describe the error here"
End If
End Sub
This validation should occurred when I press key enter on the “Siret” input field. It doesn’t seem to work actually. I wonder what is going wrong at this stage.
The best place to have a field's value changed depends on your use case. Kofax Transformation Modules follows a distinct pattern, and you should always try to follow it. For example, when you find yourself putting code in the AfterExtract method, you should reconsider -- there is almost always a better way. For a tl;dr just jump to Where to set values?
Natural Order
When you observe a field in Validation, here's what happens behind the scenes:
A locator detects information (i.e. one or more alternatives).
The locator is assigned to a field. The field will always hold the topmost alternative. By default, your field will be valid if there is only a single confident alternative, or if the second best alternative has a 20% lower confidence.
Your field may or or may not have a formatter associated with it. The formatter can make the field invalid (or even valid, if desired)
You field can be part of one or more validation rules. Validation rules can make fields valid or invalid, but they only fire if formatting was successful.
Example
Here's an example. Imagine you want to detect dates, and you want them in database format (yyyyMMdd). The dates on your documents are in US format (MM/dd/yyyy), and there are two, but the first one has "invoice date" as keyword besides it.
You configure a format locator to pick up dates, along with a keyword. The locator yields two alternatives: 01/20/2020 at 100% and 01/10/2020 at 0%.
Since the second alternative is not considered (below 10% threshold), the field will hold the first one.
Since the first alternative of the field in confident (80%), formatting is applied. The formatter changes the field's value to 20200120, and the field is still valid.
You configure a date validation method, and use said method for the field. You check whether the date is in the future or not, and let's say today's January 19. The field is now invalid since 20200120 is one day in the future.
This brings us back to the original question - where you you change a field's value? Changing it in a validation script is possible, but bear in mind that this breaks the natural order of things. Even worse, if formatting fails in the first place your code never executes.
Where to set values?
Depending on the use case, here are my recommendations:
You need to set a dynamic value, get values from an external system, or anything else that does not depend on another field/value in KTM: create a script locator and link it to your field. In script, create a new alternative and set it to the desired value. You can even make this dependent on other locators (since locators execute in sequence), but not on other fields (since fields are populated AFTER all locators have fired).
You want to normalize values. For example, days of the week should be represented by letters (SUN, MON, TUE, et cetera). You still want your users to enter numeric values (1 = SUN, 2 = MON, 3 = TUE). Create a script formatter and link it to your field. The benefit here is that you don't have to repeat yourself (for example in a script locator and later in validation).
You want to change values based on a user's interaction. You can use any event in validation (such as ButtonClicked, AfterFieldChanged or AfterFieldConfirmed), just keep in mind that some are not supported by Thin Client Validation (such as AfterFieldChanged). Keep in mind that you want to change the pointer and not the field itself since validation methods can be used by any number of fields. In your example, pXDoc.Fields.ItemByName("NAF").Text = "GOOD JOB" would violate this principle (i.e. making validation methods reusable -- your rule is now tied to the NAF field). Change the validation object instead; e.g. ValItems.ItemByName("NAF").Text = "GOOD JOB". Also keep in mind that changing a field at this point will NOT call the formatter associated with your field automatically, so make sure to provide a value that's already formatted. You can however call formatting in script manually.
Your requirement
Now, back to your original requirement:
The Objective is to set the content of a field (which is empty and required) based on a basic condition on the second field.
My objective (later) will be to fill /
update the fields based on the “Siret” field value with a database
call. My validation rule is the following : I check the “Siret” string
length (it should be a 14 chars string). If this is true, I set the
Validation to true and set the other field a value.
This depends on whether you want your users to be able to change the second field during validation. If not, go for a script locator. Note that script locators can have two subfields, and each subfield can be assigned to a different field.
If your users should be able to change it, go for multi-field script validation. Both fields should be part of the validation, and a length check should be the first thing you do. Then, if Siret has more than 14 characters, issue the database call.
A word about DRY and General Design
Not knowing your exact requirements, here are some thoughts about reusability. Let's say that Siret isn't always keyed in manually by users - in fact, a locator might pick up said text. This is where you want to create a specific method for calling the database and returning a result. Note that KTM has native support for relational databases, and you can even access this model in script.
Another alternative is to use local or remote fuzzy databases along with a database locator (again, if Siret is present on your document).
Thanks to Wolfgang and my team, I finally solved my issue.
Here is the code used to manage this :
Private Sub ValidationForm_AfterFieldConfirmed(ByVal pXDoc As CASCADELib.CscXDocument, ByVal pField As CASCADELib.CscXDocField)
Select Case pField.Name
Case "FieldNameInForm"
' simple check if field empty
If(pXDoc.Fields.ItemByName("FieldNameInForm").Text <> "") Then
completeForm(pXDoc, pXDoc.Fields.ItemByName("FieldNameInForm").Text)
End If
End Select
End Sub
Private Sub completeForm(ByVal pXDoc As CASCADELib.CscXDocument, ByVal myString As String)
'define required properties
Dim rs As ADODB.Recordset
Dim cn As ADODB.Connection
Dim sqlRequest As String
Dim dbHostServer As String
Dim dbUsername As String
Dim dbPassword As String
Dim dbName As String
Dim dbConnString As String
'Retrieve information for DB Connection (in ScriptVariables.xml)
dbHostServer = "localhost"
dbUsername = "root"
dbPassword = "root"
dbName = "mydatabase"
'build the connection string and open connection to database
dbConnString = "Provider=MSDASQL;Driver={MySQL ODBC 5.3 Unicode Driver};
dbConnString = dbConnString & "Server=" & dbHostServer & ";"
dbConnString = dbConnString & "UID=" & dbUsername & ";"
dbConnString = dbConnString & "PWD=" & dbPassword & ";"
dbConnString = dbConnString & "database=" & dbName
'Create recordset and set connection
'Prapare the db connection
Set rs = New ADODB.Recordset : : Set cn=New ADODB.Connection
cn.ConnectionString = dbConnString : cn.Open
'build query with concatenation
sqlRequest = "SELECT field1, field2, field3 FROM table"
sqlRequest = sqlRequest & " where fieldN= '" & myString & "'
'Execute the SQL request
Set rs = cn.Execute(sqlRequest)
' if the recordset returns a result
If (rs.EOF Or rs.BOF) Then
rs.MoveFirst
pXDoc.Fields.ItemByName("formField1").Text = CStr(rs.Fields("field1"))
Call ValidStrField("formField1", pXDoc.Fields.ItemByName("field1").Text, pXDoc)
pXDoc.Fields.ItemByName("formField2").Text = CStr(rs.Fields("field2"))
Call ValidStrField("formField2", pXDoc.Fields.ItemByName("field2").Text, pXDoc)
pXDoc.Fields.ItemByName("formField3").Text = CStr(rs.Fields("field3"))
Call ValidStrField("Commune", pXDoc.Fields.ItemByName("field3").Text, pXDoc)
'ifthe recordset do not return a value, we set to Undefined
Else
pXDoc.Fields.ItemByName("formField1").Text = "Undefined"
pXDoc.Fields.ItemByName("formField2").Text = "Undefined"
pXDoc.Fields.ItemByName("formField3").Text = "Undefined"
MsgBox("No result found in database")
End If
' Close connection & recordset
rs.Close : Set rs = Nothing
cn.Close : Set cn=Nothing
End Sub
' methods To validate Fields
Private Sub ValidStrField(ByVal StrItem As String,ByVal StrVal As String,ByVal pXDoc As CASCADELib.CscXDocument)
pXDoc.Fields.ItemByName(StrItem).Text = StrVal
pXDoc.Fields.ItemByName(StrItem).ExtractionConfident = True
pXDoc.Fields.ItemByName(StrItem).Confidence = 100.00
pXDoc.Fields.ItemByName(StrItem).ForcedValid = False
pXDoc.Fields.ItemByName(StrItem).Valid = True
End Sub
Private Sub UnValidStrField(ByVal StrItem As String,ByVal StrVal As String,ByVal pXDoc As CASCADELib.CscXDocument)
pXDoc.Fields.ItemByName(StrItem).Text = StrVal
pXDoc.Fields.ItemByName(StrItem).ExtractionConfident = False
pXDoc.Fields.ItemByName(StrItem).Confidence = 0.00
pXDoc.Fields.ItemByName(StrItem).ForcedValid = True
pXDoc.Fields.ItemByName(StrItem).Valid = False
End Sub

Checking 3rd character with Char.IsNumber in vb.net

I am searching a database and pulling results from it. Before displaying it in WPF I am checking the contents of the text in a field called PrimarySponsor which can be (1) blank/null (2) number at 3rd character (3) persons name. I am currently using Char.IsNumber to check option 2 if there is a number at position 4.
If reader("PrimarySponsor") Is DBNull.Value Then
resultxPrimSpon = ""
ElseIf Char.IsNumber(reader("PrimarySponsor"), 3) Then
resultxPrimSpon = "Terminated"
Else
resultxPrimSpon = reader("PrimarySponsor")
End If
Before I put the Char.IsNumber check in I was getting 4 results displaying. When i add the Char.IsNumber code I only get 2 results along with the error;
Error while connecting to SQLServer.Sepcified argument was out of the range of valid values. Parameter name: index.
Anyone have any ideas about why this is happening or how to work around it?
It's not clear where you get that error because Char.IsNumber is not a sql-server method. So i assume that it's a custom message from you. However, the "Specified argument was out of the range" is documented:
ArgumentOutOfRangeException: index is less than zero or greater than
the last position in s.
So it seems that at least one of the strings is shorter than 4 characters. In general you should store the reader values in a variable of the correct type if you have to access it more than once. In this case in a String-variable.
But it's also a good idea to create a custom type that has all properties. Then you can add all to a List(Of T). Here's an example:
Public Class Sponsor
Public Property PrimarySponsor As String
End Class
Of course you could also fill a List(Of String) instead of a List(Of Sponsor). Then you don't need to create a new type. But i assume that you have more than one column in the table. Using a custom type increases readability and maintainability much.
....
Dim allSponsors As New List(Of Sponsor)
Using reader = command.ExecuteReader()
If reader.HasRows Then
Dim primSponsorColumnIndex = reader.GetOrdinal("PrimarySponsor")
While reader.Read
Dim sponsor As New Sponsor()
If reader.IsDBNull(primSponsorColumnIndex) Then
sponsor.PrimarySponsor = ""
Else
sponsor.PrimarySponsor = reader.GetString(primSponsorColumnIndex)
If sponsor.PrimarySponsor.Length >= 4 AndAlso _
Char.IsDigit(sponsor.PrimarySponsor(3)) Then
sponsor.PrimarySponsor = "Terminated"
End If
End If
allSponsors.Add(sponsor)
End While
End If
End Using
First use DataReader.IsDBNull to check if the value is Null. Then check if Length >= 4 before you use Char.IsDigit(sponsor.PrimarySponsor(3)) to avoid the ArgumentOutOfRangeException.
Difference between Char.IsDigit() and Char.IsNumber() in C#

DateAdd + DLookup

I am requesting some guidance to fix this problem I have been having while trying to edit the "AfterUpdate" event in my database. It seems to work fine on my local machine but when I try to implement it in the network database it doesn't work properly (occasionally puts in a random date in one of the fields, doesn't erase the date when I supply a new ID, etc.)
Here is the VBA Code I have:
Private Sub provider_surveyID_AfterUpdate()
provider_survey_dueDate = DateAdd("ww", 2, DLookup("completed_on",
"qry_ProviderSurveyInfo", "provider_surveyID=" & provider_surveyID))
provider_survey_reminder2weeks = DateAdd("ww", 4, DLookup("completed_on",
"qry_ProviderSurveyInfo", "provider_surveyID=" & provider_surveyID))
provider_survey_reminder4weeks = DateAdd("ww", 6, DLookup("completed_on",
"qry_ProviderSurveyInfo", "provider_surveyID=" & provider_surveyID))
End Sub
The query is correct, joining the Survey ID to the appropriate participant to determine the original "completed_on" date that is used in the DateAdd functions.
Can you see any reason why it would not work as it does on local - removing dates when entering IDs currently not in use? Also, think it would be wise to use Nz(provider_surveyID,0) in this instance? I haven't implemented it yet as I wanted to make it work appropriately as it does on my local with no issues whatsoever - I enter for the ID, it populates; I enter 20 (not in use yet), it makes all dates null again.
Dlookups can be slow and tricky to use, it will also return random values when the Criteria isn't entered. I'm not sure on how your form is put together (I'm assuming it's a form), and this may be a partial answer:
Private Sub provider_surveyID_AfterUpdate()
Dim dtComplete as Date
If IsNull(provider_serveyID) then
provider_survey_dueDate=""
provider_survey_reminder2weeks=""
provider_survey_reminder4weeks=""
Else
dtComplete = DLookup("completed_on","qry_ProviderSurveyInfo", "provider_surveyID=" & provider_surveyID)
provider_survey_dueDate=DateAdd("ww",2,dtComplete)
provider_survey_reminder2weeks=DateAdd("ww",4,dtComplete)
provider_survey_reminder4weeks=DateAdd("ww",6,dtComplete)
End if
End sub

UPDATE statement in Oracle

We are building a client program where parameters for storage in a web server with Oracle backend are set in the .Net client program and uploaded as a dataset via webservice.
In the webservice code, data is read from the dataset and added to UPDATE statements on the web server (Oracle backend).
Because the server will run on the customer's LAN behind a firewall and because of the dynamic nature of the parameters involved, no sprocs are being used - SQL strings are built in the logic.
Here is an example string:
UPDATE WorkOrders
SET TravelTimeHours = :TravelTimeHours,
TravelTimeMinutes = :TravelTimeMinutes,
WorkTimeHours = :WorkTimeHours,
WorkTimeMinutes = :WorkTimeMinutes,
CompletedPersonID = :CompletedPersonID,
CompletedPersonName = :CompletedPersonName,
CompleteDate = :CompleteDate
WHERE WorkOrderNumber = :WorkOrderNumber
When debugging code in VS 2010 and stepping into the server code, we receive the following error:
ORA-01036: illegal variable name/number
when executing the SQL command on destination oracle machine, we were prompted to enter the bind
variables for the above statement, and as long as we used the correct date format, the UPDATE statement
worked correctly.
QUESTIONS:
1) is it possible that oracle threw the ORA-01036 error when the month format was wrong?
2) why don't we have to convert the date format from the ASP.net website running on the Oracle machine?
does Oracle have a default conversion routine that excludes the bind variable entry screen?
3) if the date format was not the problem, what precisely does ORA-1036 mean and how do I discover
WHICH variable had an illegal name/number?
This is a snippet of a function that takes the type of the dataset (WOName) and returns the appropriate SQL string.
Many Cases exist but have been removed for readability.
Private Function GetMainSQLString(ByVal WOName As String) As String
Dim Result As String = ""
Select Case WOName
Case "Monthly Site Inspection"
Dim sb As New StringBuilder
sb.Append("UPDATE WorkOrders SET ")
sb.Append("CompletedPersonID = :CompletedPersonID, CompletedPersonName = :CompletedPersonName, CompleteDate = :CompleteDate, ")
sb.Append("SupervisorID = :SupervisorID, SupervisorName = :SupervisorName ")
sb.Append("WHERE WorkOrderNumber = :WorkOrderNumber")
Result = sb.ToString
End Select
Return Result
End Function
This is a snippet of a function that takes the Oracle command object byRef and adds the required parameters to it,
depending upon which of the possible 15 types of dataset(WOName) is received from the client program.
Many Cases exist but have been removed for readability.
The updated Cmd object is then returned to the main program logic, where ExecuteNonQuery() is called.
The test values of params below are as follows:
dr.Item("CompletedPersonID") 21
dr.Item("CompletedPersonName") Pers Name
dr.Item("CompleteDate") #8/16/2010#
dr.Item("SupervisorID") 24
dr.Item("SupervisorName") Sup Name
dr.Item("WorkOrderNumber") 100816101830
Private Function addMainCmdParams(ByVal WOName As String, ByRef cmd As OracleCommand, ByVal dr As DataRow) As OracleCommand
Select Case WOName
Case "Monthly Site Inspection"
cmd.Parameters.Add(":CompletedPersonID", Oracle.DataAccess.Client.OracleDbType.Int32).Value = dr.Item("CompletedPersonID")
cmd.Parameters.Add(":CompletedPersonName", Oracle.DataAccess.Client.OracleDbType.Varchar2).Value = dr.Item("CompletedPersonName")
cmd.Parameters.Add(":CompleteDate", Oracle.DataAccess.Client.OracleDbType.Date).Value = dr.Item("CompleteDate")
cmd.Parameters.Add(":SupervisorID", Oracle.DataAccess.Client.OracleDbType.Int32).Value = dr.Item("SupervisorID")
cmd.Parameters.Add(":SupervisorName", Oracle.DataAccess.Client.OracleDbType.Varchar2).Value = dr.Item("SupervisorName")
cmd.Parameters.Add(":WorkOrderNumber", Oracle.DataAccess.Client.OracleDbType.Varchar2).Value = dr.Item("WorkOrderNumber")
End Select
Return cmd
End Function
While running this today, this precise code WAS successful; but another similar case was not. I still distrust any implicit typecasting performed by Oracle (if any) - and I'm especially suspicious of how Oracle handles any of these parameters that are passed with a dbNull.value - and I know it's going to happen. so if that's the problem I'll have to work around it. There are too many optional parameters and columns that don't always get values passed in for this system to break on nulls.
One Oracle "gotcha" that can cause this error is the fact that, by default, Oracle maps parameters to parameter symbols in the query by sequence, not by name. If the number/type of parameters does not match, you get an error like this one.
The solution is to tell Oracle to bind by name:
cmd.BindByName = true
Without diving into the details of your code, this may or may not be the answer to your specific problem, but this setting should be the default, and should be part of any command setup that uses parameters. It's rather amazing to watch this one statement fix some obscure problems.
EDIT: This assumes that you're using Oracle's data access provider. In .NET, you should be using this, not Microsoft's Oracle provider.
The error has nothing to do with date formats, it means that a variable in the statement was not bound.
Could be as simple as a spelling mistake (would be nice if Oracle included the variable name in the error message).
Can you update your question with the surrounding code that creates, binds, and executes the statement?
This is a snippet of a function that takes the type of the dataset (WOName) and returns the appropriate SQL string.
Many Cases exist but have been removed for readability.
Private Function GetMainSQLString(ByVal WOName As String) As String
Dim Result As String = ""
Select Case WOName
Case "Monthly Site Inspection"
Dim sb As New StringBuilder
sb.Append("UPDATE WorkOrders SET ")
sb.Append("CompletedPersonID = :CompletedPersonID, CompletedPersonName = :CompletedPersonName, CompleteDate = :CompleteDate, ")
sb.Append("SupervisorID = :SupervisorID, SupervisorName = :SupervisorName ")
sb.Append("WHERE WorkOrderNumber = :WorkOrderNumber")
Result = sb.ToString
End Select
Return Result
End Function
This is a snippet of a function that takes the Oracle command object byRef and adds the required parameters to it,
depending upon which of the possible 15 types of dataset(WOName) is received from the client program.
Many Cases exist but have been removed for readability.
The updated Cmd object is then returned to the main program logic, where ExecuteNonQuery() is called.
The test values of params below are as follows:
dr.Item("CompletedPersonID") 21
dr.Item("CompletedPersonName") Pers Name
dr.Item("CompleteDate") #8/16/2010#
dr.Item("SupervisorID") 24
dr.Item("SupervisorName") Sup Name
dr.Item("WorkOrderNumber") 100816101830
Private Function addMainCmdParams(ByVal WOName As String, ByRef cmd As OracleCommand, ByVal dr As DataRow) As OracleCommand
Select Case WOName
Case "Monthly Site Inspection"
cmd.Parameters.Add(":CompletedPersonID", Oracle.DataAccess.Client.OracleDbType.Int32).Value = dr.Item("CompletedPersonID")
cmd.Parameters.Add(":CompletedPersonName", Oracle.DataAccess.Client.OracleDbType.Varchar2).Value = dr.Item("CompletedPersonName")
cmd.Parameters.Add(":CompleteDate", Oracle.DataAccess.Client.OracleDbType.Date).Value = dr.Item("CompleteDate")
cmd.Parameters.Add(":SupervisorID", Oracle.DataAccess.Client.OracleDbType.Int32).Value = dr.Item("SupervisorID")
cmd.Parameters.Add(":SupervisorName", Oracle.DataAccess.Client.OracleDbType.Varchar2).Value = dr.Item("SupervisorName")
cmd.Parameters.Add(":WorkOrderNumber", Oracle.DataAccess.Client.OracleDbType.Varchar2).Value = dr.Item("WorkOrderNumber")
End Select
Return cmd
End Function
While running this today, this precise code WAS successful; but another similar case was not. I still distrust any implicit typecasting performed by Oracle (if any) - and I'm especially suspicious of how Oracle handles any of these parameters that are passed with a dbNull.value - and I know it's going to happen. so if that's the problem I'll have to work around it. There are too many optional parameters and columns that don't always get values passed in for this system to break on nulls.

ComboBox DataBinding DisplayMember and LINQ queries

Update
I decided to iterate through the Data.DataTable and trimmed the values there.
Utilizing SirDemon's post, I have updated the code a little bit:
Sub test(ByVal path As String)
Dim oData As GSDataObject = GetDataObj(path)
EmptyComboBoxes()
Dim oDT As New Data.DataTable
Try
Dim t = From r In oData.GetTable(String.Format("SELECT * FROM {0}gsobj\paths ORDER BY keyid", AddBS(path))) Select r
If t.Count > 0 Then
oDT = t.CopyToDataTable
For Each dr As Data.DataRow In oDT.Rows
dr.Item("key_code") = dr.Item("key_code").ToString.Trim
dr.Item("descript") = dr.Item("descript").ToString.Trim
Next
dataPathComboBox.DataSource = oDT
dataPathComboBox.DisplayMember = "descript"
dataPathComboBox.ValueMember = "key_code"
dataPathComboBox.SelectedIndex = 0
dataPathComboBox.Enabled = True
End If
Catch ex As Exception
End Try
End Sub
This works almost as I need it to, the data is originally from a foxpro table, so the strings it returns are <value> plus (<Field>.maxlength-<value>.length) of trailing whitespace characters. For example, a field with a 12 character length has a value of bob. When I query the database, I get "bob_________", where _ is a space.
I have tried a couple of different things to get rid of the whitespace such as:
dataPathComboBox.DisplayMember.Trim()
dataPathComboBox.DisplayMember = "descript".Trim.
But nothing has worked yet. Other than iterating through the Data.DataTable or creating a custom CopyToDataTable method, is there any way I can trim the values? Perhaps it can be done in-line with the LINQ query?
Here is the code I have so far, I have no problem querying the database and getting the information, but I cannot figure out how to display the proper text in the ComboBox list. I always get System.Data.DataRow :
Try
Dim t = From r In oData.GetTable("SELECT * FROM ../gsobj/paths ORDER BY keyid") _
Select r
dataPathComboBox.DataSource = t.ToList
dataPathComboBox.SelectedIndex = 0
'dataPathComboBox.DisplayMember = t.ToList.First.Item("descript")
dataPathComboBox.Enabled = True
Catch ex As Exception
Stop
End Try
I know that on the DisplayMember line the .First.Item() part is wrong, I just wanted to show what row I am trying to designate as the DisplayMember.
I'm pretty sure your code tries to set an entire DataRow to a property that is simply the name of the Field (in a strongly type class) or a Column (in a DataTable).
dataPathComboBox.DisplayMember = "descript"
Should work if the DataTable contains a retrieved column of that name.
Also, I'd suggest setting your SelectedIndex only AFTER you've done the DataBinding and you know you actually have items, otherwise SelectedIndex = 0 may throw an exception.
EDIT: Trimming the name of the bound column will trim just that, not the actual bound value string. You either have to go through all the items after they've been bound and do something like:
dataPathComboBox.Item[i].Text = dataPathComboBox.Item[i].Text.Trim()
For each one of the items. Not sure what ComboBox control you're using, so the item collection name might be something else.
Another solution is doing that for each item when it is bound if the ComboBox control exposes an onItemDataBound event of some kind.
There are plenty of other ways to do this, depending on what the control itself offers and what you choose to do.
DisplayMember is intended to indicate the name of the property holding the value to be displayed.
In your case, I'm not sure what the syntax will by since you seem to be using a DataSet, but that should be
... DisplayMember="Item['descript']" ...
in Xaml, unless you need to switch that at runtime in which case you can do it in code with
dataPathComboBox.DisplayMember = "Item['descript']"
Again, not 100% sure on the syntax. If you are using a strongly typed DataSet it's even easier since you should have a "descript" property on your row, but given hat your error indicates "System.DataRow" and not a custom type, I guess you are not.
Because I can't figure out the underlying type of the datasource you are using I suggest you to change commented string to
dataPathComboBox.DisplayMember = t.ElementType.GetProperties.GetValue(0).Name
and try to determine correct index (initially it is zero) in practice.