Importing a spreadsheet, but having trouble - asp.net

I have a form that allows a user to import a spreadsheet. This spreadsheet is generally static when it comes to column headers, but now the users want to be able to include an optional column (called Notes). My code crashes when I try to read the column from the spreadsheet if it doesn't exist.
Dim objCommand As New OleDbCommand()
objCommand = ExcelConnection() 'function that opens spreadsheet and returns objCommand
Dim reader As OleDbDataReader
reader = objCommand.ExecuteReader()
While reader.Read()
Dim Employee As String = Convert.ToString(reader("User"))
Dim SerialNUM As String = Convert.ToString(reader("serialno"))
**Dim Notes As String = Convert.ToString(reader("notes"))**
If the spreadsheet contains a Notes column, all goes well. If not, crash. How can I check to see if the Notes column exists in the spreadsheet to avoid the crash?

Change the code to something like this:
[EDIT - changed code logic)
Dim fieldCount = reader.FieldCount
For i = 0 To fieldCount - 1
Dim colName = reader.GetName(i)
If (colName = "notes") Then
Dim Notes As String = reader.GetString(i)
End If
Next i

Perhaps OleDbDataReader.FieldCount could help you program a workaround.

Related

How can I add a scalar variable for an SQL command In a function that doesn't house my query directly?

I will try to keep this as brief as possible.
I have a function called GetData(ByVal query As String) whose sole purpose is to populate a data table multiple times based on certain conditions. As you can see, the function accepts a string variable where the SQL statement resides. What I am trying to do is add a scalar variable, "#date" in my case, and no matter where I try to add this variable it throws an error stating "Must declare scalar variable #date.
Edit: I should mention that it is throwing the "must declare variable" error on the sda.Fill(dt) line.
GetData Function
Private Shared Function GetData(ByVal query As String) As DataTable
Dim constr As String = ConfigurationManager.ConnectionStrings("WarrantyConnectionString").ConnectionString
Using con As SqlConnection = New SqlConnection(constr)
Using cmd As SqlCommand = New SqlCommand(query)
Dim dt As DataTable = New DataTable()
cmd.Parameters.Add("#date", SqlDbType.Date).Value = Date.Today
Using sda As SqlDataAdapter = New SqlDataAdapter(query, con)
cmd.Parameters.AddWithValue("#date", Date.Today)
sda.Fill(dt)
End Using
Return dt
End Using
End Using
End Function
I am calling the function in a procedure that has the query and handles all of the conditions I need.
Procedure
Dim queryStart As String = "SELECT ( SELECT SUM(DealerNet) FROM Agreement WHERE VoidDate IS NULL "
Dim queryAlias As String = "AS Actual, "
Dim queryStart2 As String = "(SELECT SUM(Amount) FROM AccountingUS.dbo.ProjectedSales "
Dim queryAlias2 As String = "AS Projected "
If chart = "pmtd" Then
Dim queryCondition As String = "AND IssueDate BETWEEN (SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, #date)-1, 0)) AND #date) "
Dim queryCondition2 As String = "WHERE [Month] = MONTH(#date) AND [Year] = YEAR(#date)) "
Dim query As String = queryStart + queryCondition + queryAlias + queryStart2 + queryCondition2 + queryAlias2
Dim xMember1 As String = "Actual"
Dim xMember2 As String = "Projected"
Dim dt As DataTable = GetData(query)
pmtdChart.DataSource = dt
The variable in question is the #date variable in the strings within the "If" statement, the only value it holds is todays date. Currently, I have tried to use "cmd.Parameters.Add("#date", SqlDbType.Date).Value = Date.Today in the GetData function, however, I still receive the same "Must declare scalar variable" error. I have also tried replacing the #date variable with simply "" + Date.Today + "" or a variable that holds todays date, but upon doing so I receive an operand error about "Operand Clash: Date is incompatible with Int"
Any help regarding this issue would be greatly appreciated, I am relatively new to programming and would appreciate any tips or criticisms regarding best practices. If you need any additional information or clarification regarding this issue I would be happy to provide what I can. Thank you in advance.
Ok, a few things:
I would actually pass a command object to that get data routine.
And your issue is you feeding the query to the "adaptor", but NOT supplying the #date parameter to that "sda"
this:
Using sda As SqlDataAdapter = New SqlDataAdapter(query, con)
cmd.Parameters.AddWithValue("#date", Date.Today)
sda.Fill(dt)
End Using
In other words, you NOT EVEN using the cmd object!!!
So, you would need to add the parameter's to the sda object!!
eg this:
Public Function GetData(ByVal query As String) As DataTable
Dim dt As DataTable = New DataTable()
Dim constr As String =
ConfigurationManager.ConnectionStrings("WarrantyConnectionString").ConnectionString
Using con As SqlConnection = New SqlConnection(constr)
Using sda As SqlDataAdapter = New SqlDataAdapter(query, con)
sda.SelectCommand.Parameters.Add("#date", SqlDbType.Date).Value = Date.Today()
sda.Fill(dt)
End Using
End Using
Return dt
End Function
So, yes, you WILL get that error about "#date" not being declared, since you NOT using the cmd object to fill the table, but are using the data adaptor.
So, as a future suggest?
Pick one way, or the other way.
I MUCH over the years have decided that I will use/have/adopt and cookie cut over and over the SqlCommand object.
I find the Sql cmd object better, since:
it has the parameters.
it has a connection object (if you want to use)
it has a data reader built in
So, what this means?
I suggest this code for get data:
Private Shared Function GetData(ByVal query As String) As DataTable
Dim constr As String =
ConfigurationManager.ConnectionStrings("WarrantyConnectionString").ConnectionString
Dim dt As DataTable = New DataTable()
Using con As SqlConnection = New SqlConnection(constr)
Using cmd As SqlCommand = New SqlCommand(query, con))
con.Open()
cmd.Parameters.Add("#date", SqlDbType.Date).Value = Date.Today
dt.Load(cmd.ExecuteReader)
End Using
End Using
Return dt
End Function
So, we don't need a data adaptor. In fact, you only need a adaptor if you going to update the resulting table (think a "adaptive" table to remember this). You not going to update the data, so really, no need to use a "adaptor" at all here. (and sadly, far too many examples use a "adaptor" anyway. They are for ALLOWING update of the data table, and you not doing that!
So, use a command object. Do note that you ALWAYS must then open the confection, but since we have "using" blocks, it will ALWAYS be closed for you.
And note how then we don't create to "use" the "reader" from the adaptor, nor a fill command. (so, we eliminated one whole confusing object!!).
So, in your example, you created a SQL command object, correctly added the parameter to the command object, but THEN DON'T use it, and then decided to create a data adaptor, and use that!!!
So, you could/can leave your code as you had with the sda "prameter " fix I posted above.
However, but I think your better off to use a sql command object.
Note even better?
Pass the command object to the GetData routine.
I have a global "general" purpose routine called MyRstP(), and I pass it a command object, even for just plain jane sql.
but, if you decide to add parameter's, you can!
Do note that parameter's can be added 100% independent of the SQL string, and they can be added before, or after you set the sql string.
And you can add parameter's WITHOUT a valid working connection (or have created one just yet). So, "parameters" are just a colleciton - it does not care about the SQL (well, at least not yet!!).
So, here is my RstP, and I dumped this into a plain jane "module1" which VB has (this means you don't have to create a static class, and this works then just like VB6, or VBA.
So, this:
Public Function MyRstP(cmdSQL As SqlCommand, ByVal Optional strCon As String = "") As DataTable
If strCon = "" Then
strCon = My.Settings.TEST4
End If
Dim rstData As New DataTable
Using conn As New SqlConnection(strCon)
Using (cmdSQL)
cmdSQL.Connection = conn
conn.Open()
rstData.Load(cmdSQL.ExecuteReader)
End Using
End Using
Return rstData
End Function
So, now to say fill a grid view, I use this:
Dim strSQL As String =
"SELECT id, HotelName, City FROM tblHotelsA"
Dim cmdSQL As New SqlCommand(strSQL)
GridView1.DataSource = MyRstP(cmdSQL)
GridView1.DataBind()
or say a given date of some such:
How about all hotel visit dates from start of year.
So, this:
Dim strSQL As String =
"SELECT id, HotelName, City FROM tblHotelsA
WHERE VisitDate >= #dtStart"
Dim dtStart As DateTime
dtStart = DateSerial(DateTime.Today.Year, 1, 1)
Dim cmdSQL As New SqlCommand(strSQL)
cmdSQL.Parameters.Add("#dtStart", SqlDbType.DateTime).Value = dtStart
GridView1.DataSource = MyRstP(cmdSQL)
GridView1.DataBind()
note then how I have that MyRstP (like your get data), but I can pass it quite much anything I want, including parameter's from the "calling" code, NOT in that general routine.
Anyway, the above use and adding the parameter's to the "adaptor" will fix this, but I would change over to using just a command object and a connection - the adaptor really not required, and as noted, they really are to be used WHEN you actually want to update the data table, and then send it back to the database in one shot.
If you look closely, you setup a cmd command, but you never actually pass it to the DataTable. So it doesn't know anything about your params.
How about this instead (copied untested from Trying to pass SqlCommand in SqlDataAdapter as parameters):
DataTable dt = new DataTable();
using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings("WarrantyConnectionString").ConnectionString))
{
con.Open();
using (SqlCommand cmd = con.CreateCommand())
{
cmd.CommandText = query;
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add("#date", SqlDbType.Date)
cmd.Parameters.AddWithValue("#date", Date.Today)
using (SqlDataAdapter adp = new SqlDataAdapter(cmd))
{
adp.Fill(dt);
return dt;
}
}
}
Dim dt as new DataTable()
using db as new SqlConnection(ConfigurationManager.ConnectionStrings("WarrantyConnectionString").ConnectionString)
db.Open();
using cmd as New SqlCommand(query, con)
cmd.Parameters.Add("#date", SqlDbType.Date).value = Date.Today
//cmd.Parameters.AddWithValue("#date", Date.Today)
using adp as new SqlDataAdapter(cmd)
adp.Fill(dt)
return dt
End using
End using
End using

Open XML SDK Open and Save not working

I am having trouble with the Open XML SDK opening and saving word documents.
I am using the following code (VB.Net):
Try
'Set Path
Dim openPath As String = "../Documents/" & worddoc
Dim savePath As String = "\\web-dev-1\HR_Documents\" & worddoc
Using doc As WordprocessingDocument = WordprocessingDocument.Open("/Documents/" & worddoc, True)
'Employee Name Insert
'Find first table in document
Dim tbl1 As Table = doc.MainDocumentPart.Document.Body.Elements(Of Table).First()
'First Row in tbl
Dim row As TableRow = tbl1.Elements(Of TableRow)().ElementAt(0)
'Find first cell in row
Dim cell As TableCell = row.Elements(Of TableCell)().ElementAt(0)
'Insert selected Employee Name
Dim p As Paragraph = cell.Elements(Of Paragraph)().First()
Dim r As Run = p.Elements(Of Run)().First()
Dim txt As Text = r.Elements(Of Text)().First()
txt.Text = ddlEmployeeList.SelectedItem.Text
'Save File
'Supervisor Name Insert
'Find second table in document
Dim tbl2 As Table = doc.MainDocumentPart.Document.Body.Elements(Of Table).First()
'First Row in tbl
Dim row2 As TableRow = tbl2.Elements(Of TableRow)().ElementAt(0)
'Find first cell in row
Dim cell2 As TableCell = row2.Elements(Of TableCell)().ElementAt(0)
'Insert selected Employee Name
Dim p2 As Paragraph = cell2.Elements(Of Paragraph)().First()
Dim r2 As Run = p2.Elements(Of Run)().First()
Dim txt2 As Text = r2.Elements(Of Text)().First()
txt2.Text = ddlSupervisorList.SelectedItem.Text
End Using
Return 1
Catch ex As Exception
Return Nothing
End Try
The trouble starts on the first using statement. It throws the following error:
Could not find a part of the path 'C:\Documents\Hourly_Employee_Performance_Review .docx
I have placed the word documents in a folder of the ASP.NET site called Documents. I also have created a public share on the dev server to see if maybe that would help.
The problem is that it doesn't use the supplied path variable. I have gone through the documentation for OPEN XMl SDK but all it talks about is the Using Statement and its need and use for it.
Can anyone tell me, show me, or point to a site that has examples of how to set both the open path and save path?
You need a path to the file which is based on the filesytem, not a URL. You can do that with
Dim openPath As String = Path.Combine(Server.MapPath("~/Documents"), worddoc)
And then to open the file:
Using doc As WordprocessingDocument = WordprocessingDocument.Open(openPath, True)
It appears that you will need to do the same for the location to save to, but you didn't say if "\\web-dev-1" is a different server; if it were that would need other considerations.
(Not tested, some typos may exist. You will need an Imports System.IO.)

Converting string to XML node in VB.NET

I've an XML string in database column like this
<trueFalseQuestion id="585" status="correct" maxPoints="10"
maxAttempts="1"
awardedPoints="10"
usedAttempts="1"
xmlns="http://www.ispringsolutions.com/ispring/quizbuilder/quizresults">
<direction>You have NO control over how you treat customers.</direction>
<answers correctAnswerIndex="1" userAnswerIndex="1">
<answer>True</answer>
<answer>False</answer>
</answers>
</trueFalseQuestion>
But I need to do XML operations on this string like select its name, attributes values,inner text etc. How can I make this possible from this string
EDIT
Im sharing the code snippet I tried, but not working
Dim myXML As String
Dim gDt As New DataTable
gDt.Columns.Add("id")
gDt.Columns.Add("questionid")
gDt.Columns.Add("serial")
gDt.Columns.Add("direction")
Dim dr As DataRow
myXML ='<my above shared XML>'
Dim xmlDoc As New XmlDocument
xmlDoc.LoadXml(myXML)
dr = gDt.NewRow
dr("serial") = 1
dr("id") = xmlDoc.Attributes("id").Value
dr("direction") = xmlDoc("direction").InnerText
gDt.Rows.Add(dr)
But thats not working at all as I wish
There are many ways to parse XML in .NET, such as using one of the serialization classes or the XmlReader class, but the two most popular options would be to parse it with either XElement or XmlDocument. For instance:
Dim input As String = "<trueFalseQuestion id=""585"" status=""correct"" maxPoints=""10"" maxAttempts=""1"" awardedPoints=""10"" usedAttempts=""1"" xmlns=""http://www.ispringsolutions.com/ispring/quizbuilder/quizresults""><direction>You have NO control over how you treat customers.</direction><answers correctAnswerIndex=""1"" userAnswerIndex=""1""><answer>True</answer><answer>False</answer></answers></trueFalseQuestion>"
Dim element As XElement = XElement.Parse(input)
Dim id As String = element.#id
Or:
Dim input As String = "<trueFalseQuestion id=""585"" status=""correct"" maxPoints=""10"" maxAttempts=""1"" awardedPoints=""10"" usedAttempts=""1"" xmlns=""http://www.ispringsolutions.com/ispring/quizbuilder/quizresults""><direction>You have NO control over how you treat customers.</direction><answers correctAnswerIndex=""1"" userAnswerIndex=""1""><answer>True</answer><answer>False</answer></answers></trueFalseQuestion>"
Dim doc As New XmlDocument()
doc.LoadXml(input)
Dim nsmgr As New XmlNamespaceManager(doc.NameTable)
nsmgr.AddNamespace("q", "http://www.ispringsolutions.com/ispring/quizbuilder/quizresults")
Dim id As String = doc.SelectSingleNode("/q:trueFalseQuestion/#id", nsmgr).InnerText
Based on your updated question, it looks like the trouble you were having is that you weren't properly specifying the namespace. If you use XElement, it's much more forgiving (i.e. loose), but when you use XPath to select nodes in an XmlDocument, you need to specify every namespace, even when it's the default namespace on the top-level element of the document.

Get Oracle.DataAccess.Types.OracleClob instead of actual value

I'm having an issue, I'm calling a procedure on oracle 11g, the prucedure receives a clob and responds with a different CLOB, a VARCHAR2 and a Number. The procedure is called from a ASP.NET (on Visual Basic) webpage using oracle data provider (ODP.NET), I can call the procedure successfully, view the VARCHAR2 and NUMBER returned values, but when I try to see the returned value of the returning CLOB all I get is "Oracle.DataAccess.Types.OracleClob" instead of a expecting XML
I know the returned XML is generated because on the store procedure I create a txt file where it shows the expected result
My code it's pretty simple right now:
Function Index() As String 'ActionResult
Dim xml_message As String
Dim oradb As String = "Data Source=127.0.0.1;User Id=id;Password=pass;"
Dim conn As New OracleConnection(oradb)
Dim oracleDataAdapter As New OracleDataAdapter
oracleDataAdapter = New OracleDataAdapter()
Dim cmd As New OracleCommand
cmd.Connection = conn
cmd.CommandType = CommandType.StoredProcedure
cmd.CommandText = "Common.GetDriverPoints"
cmd.BindByName = True
Dim driver_input As New OracleParameter()
driver_input = cmd.Parameters.Add("p_driver", OracleDbType.Clob)
driver_input.Direction = ParameterDirection.Input
driver_input.Value = <THE_SENDED_XML_VALUE>
Dim driver_output As New OracleParameter()
driver_output = cmd.Parameters.Add("p_output", OracleDbType.Clob)
driver_output.Direction = ParameterDirection.Output
Dim error_flag As New OracleParameter()
error_flag = cmd.Parameters.Add("p_Return", OracleDbType.Int16)
error_flag.Direction = ParameterDirection.Output
Dim error_desc As New OracleParameter()
error_desc = cmd.Parameters.Add("p_ReturnDesc", OracleDbType.Varchar2, 100)
error_desc.Direction = ParameterDirection.Output
conn.Open()
cmd.ExecuteNonQuery()
Dim output As String
output = driver_output.Value.ToString() 'This only returns Oracle.DataAccess.Types.OracleClob
conn.Close()
conn.Dispose()
Return output
End Function
Also, the generated xml is around 55Kb, sometimes it's bigger
Thank you
I manage to find the answer, In case someone have the same problem, basically what has to be done is create another clob, used only on for vb.net, that clob will receive the value of the parameter output from the procedure, then cast to a string variable the local clob.
Example:
Dim output As String
Dim myOracleClob As OracleClob = driver_output.Value
output = System.Convert.ToString(myOracleClob.Value)
Now the "output" variable holds the actual message of the clob.
Hope this helps anybody with the same problem.

Using a stringbuilder as a parameter to a stored procedure and returning a dataset

I have a couple of problems relating to one of the parameters passing a number of values to a stored procedure and the result that comes back converting to dataset in order for this to be bound to an MS ReportViewer.
The error I am getting says that the the reader is closed.
My relevant code snippet is:
Dim _listOfSites As New StringBuilder()
Dim _resultDataSet As DataSet = New DataSet
Using _conn as New SqlConnection()
_conn.ConnectionString = _connString
Try
For i as Integer = 0 To _sites.Count - 1
_listOfSites.Append(_sites(i))
If _sites.Count > 1 Then
_listOfSites.Append(",")
End If
Next
_conn.Open()
Dim _sqlCommand as SqlCommand = New SqlCommand("GetResults", _conn)
_sqlCommand.Parameters.Add("#Sites", SqlDbType.Varchar).Value = _listOfSites
_sqlCommand.Parameters.Add("#Date", SqlDbType.Date).Value = _date
Dim _reader as SqlDataReader = _sqlCommand.ExecuteReader
While _reader.Read
_resultDataSet.Load(_reader, LoadOption.PreserveChanges, New String() {"RegionalResults"})
End While
_reader.Close()
Can anyone please help?
Thanks
Looks like you should not call _reader.Read as _resultDataSet.Load do it by itself and it could close the SqlDataReader. So instead of
Dim _reader as SqlDataReader = _sqlCommand.ExecuteReader
While _reader.Read
_resultDataSet.Load(_reader, LoadOption.PreserveChanges, New String() {"RegionalResults"})
End While
_reader.Close()
Just write
Using _reader as SqlDataReader = _sqlCommand.ExecuteReader
_resultDataSet.Load(_reader, LoadOption.PreserveChanges, New String() {"RegionalResults"})
End Using
Hope that helps

Resources