Set rslistings = my_conn.Execute(strSQL)
Do while NOT rslistings.Eof
description = strip(rslistings("description"))
rslistings.MoveNext
loop
In strip - NULL is being passed. However, if I attach a debugger and inspect the contents of rslistings("description"), then the actual Field object is passed through
It's quite old asp code, but it works on IIS6, just not IIS7
EDIT This only happens on the "description" field with is a text type (MySQL database)
strip doesn't do a lot:
If NOT IsNull(passedinvalue) Then
// do something
Else
// do something else
If I call strip like strip(rs("description")), it is never null as the Field object is passed in. If I assign it to another value, then pass it in (like strip(mynewvar)) then the correct value is passed in.
Edit - database bits as requested below
Set my_conn = Server.CreateObject("ADODB.Connection")
Set rs = Server.CreateObject("ADODB.Recordset")
my_conn.Open "DSN=mydb"
SQL
Set rs = my_conn.Execute("SELECT description FROM table")
the Field Collection is the default member of the Recordset object.
so is the value property for the Field object.
so the following two code statements are equivalent.
Debug.Print objRs.Fields.Item(0) ' Both statements print
Debug.Print objRs(0) ' the Value of Item(0).
it is a difference if you assign a value to a variable or use it as a parameter in a function.
#Paul: If strip doesn't check if description is NULL before working on it, you could do this --
Do while NOT rslistings.Eof
description = rslistings("description")
If NOT IsNull(description) Then
description = strip(description)
Else
description = "" ' or you could have description = " "
' if you output to screen later on
End If
rslistings.MoveNext
loop
Related
In my SQL database, I've declared DpsDate and AdmDate as DATE, also I've set them to allow nulls. When I run my application and leave these columns blank, I get this error:
Failed to convert parameter value from a String to a DateTime.
This is where I'm a bit confused because I've set them to allow nulls so shouldn't the database accept no value? The application works if I set both dates to "01/01/1900". I've tried setting them to "00/00/0000" but I get the same error.
Here's what I have:
If tbNotifyDate.Text = "" Then
cmd.Parameters.Add("#DpsDate", SqlDbType.Date, 50).Value = "01/01/1900"
Else
cmd.Parameters.Add("#DpsDate", SqlDbType.Date, 50).Value = tbNotifyDate.Text
End If
If tbAdmDate.Text = "" Then
cmd.Parameters.Add("#AdmDate", SqlDbType.Date, 50).Value = "01/01/1900"
Else
cmd.Parameters.Add("#AdmDate", SqlDbType.Date, 50).Value = tbAdmDate.Text
End If
You need to use DBNull.Value to represent NULL in ADO.NET. Things like table adapters and Entity Framework, which are built on top of ADO.NET, can support nullable value types and thus use Nothing to represent NULL but ADO.NET itself predates nullable value types, so Microsoft had to invent a type specifically for the purpose of representing NULL.
I would suggest using the If operator to make the code more concise:
Dim value As Date
cmd.Parameters.Add("#AdmDate", SqlDbType.Date).Value = If(Date.TryParse(tbAdmDate.Text, value),
value,
CObj(DBNull.Value))
The CObj is required because the two possible results of If must be the same type and Date and DBNull are not the same type. By casting one possible result as type Object, they are both interpreted as type Object and the compiler is happy.
Note that, as I have written that example, this will save NULL if the TextBox contains anything that isn't a valid representation of a Date. You can use whatever validation is appropriate in your specific case or, if you've already validated, just check for an empty TextBox and use CDate.
I'm using Classic ASP. I have a wrapper function for database queries that accepts a query string and an array of parameters, and auto-creates the proper query object and runs the query. Very handy and has been working great.
Here's my problem: When testing, I often want to see the exact text of the query being passed to SQL. Back in the "bad old days" of assembling queries through concatenation I could just write out the string. Now that I'm using parameterization it's a bit more tricky.
How do I take a peek at the fully-assembled query string just before it's passed to the database connection?
Here is the function I'm using, simplified. (The actual function doesn't assume string, for example.)
Public Function pquery( strQuery, params )
Dim cmd, param, thisParam, rs
Set cmd = Server.CreateObject( "ADODB.Command" )
cmd.ActiveConnection = MyConn
cmd.CommandText = strQuery
If IsArray( params ) then
Dim adVarChar : adVarChar = 200
For Each param In params
Set thisParam = cmd.CreateParameter( "#p", adVarChar, , len( param ), param )
cmd.Parameters.Append thisParam
Next
End If
Set rs = cmd.Execute
Set pquery = rs
End Function
I would consider using Sql Query Profiler, as it'll allow you to view the sql text as well as the values being passed in. It'll allow you to set breakpoints, as well as see how long it takes to run a query. However, this requires the query to be sent to the actual database (you had asked for before).
To do it beforehand, you would need to loop through the parameters collection in the command object, then do a find/replace with the key/value pairs in the command text property. it would be hackish at best, if you can use Profiler, go with that.
Can anyone help me explain the following problem
In a SQL-query I get info about the occurrence of an id from another table.
Everything works here and I show a crucial snippet below
set rsRecordCount = Cn.execute(mysql_query)
dim cnt
cnt = rsRecordCount("TotalRecords")
response.write("cnt " & cnt & " id = " & id & "<br>")
rsRecordCount.Close
set rsRecordCount = nothing
So - via response.write I get info about the occurrence. The problem arises
when I want to test the cnt variable
if cnt = 0 then
response.write(".....<br>")
end if
just a simple test, the code stops execute here and I wonder why? I first thought cnt might work like a pointer pointing to a recordset and when setting it to null it would be error or undefined behaviour? But I've tried to comment out .Close and = nothing. The problem is still there.
Its really the cnt that is the prolem, If I use antoher variable - the code works again
if blablabla = 0 then
response.write("it works now<br>")
end if
How do I get around this/what did I miss
thanks!!!
I first thought cnt might work like a pointer pointing to a recordset
You were right in this assumption, but not 100% accurate. The default property of Recordset object returns a Field object, i.e. after this line:
cnt = rsRecordCount("TotalRecords")
The variable cnt is actually a Field object. Now you ask, why this line "works"?
response.write("cnt " & cnt & " id = " & id & "<br>")
That's because the Field object returns its Value property when being treated as a String.
However, when trying to compare to integer, VBScript fails to find any proper conversion and chokes.
There are two common ways to solve such a thing:
Convert the value to integer using CInt or CLng:
cnt = CLng(rsRecordCount("TotalRecords"))
Like the Response.Write above, this one first converts to String, then to Long. Profit.
Take the actual value, not the Field object:
cnt = rsRecordCount.Fields("TotalRecords").Value
Personally, I think the second way is more elegant and readable. Both ways work. Good luck!
I have a gridview with a checkbox, that when selected inserts the selected items into two databases. The error occurs at a specific insert parameter that is a data type nvarchar. I'm not sure why it's giving me a boolean error. Any help would be greatly appreciated, I can post code if needed.
Okay, so let's get started. First, this has got to change from this:
sqlds1.UpdateCommand = String.Format(
"UPDATE Fees SET Inactive = '1' WHERE Description = '{0}'",
Request("cbusno"))
to this:
sqlds1.UpdateCommand = "UPDATE Fees SET Inactive = '1' WHERE Description = #Desc"
sqlds1.UpdateCommand.Parameters.AddWithValue("#Desc", Request("cbusno"))
Next, this has got to change from this:
sqlds2.UpdateCommand = String.Format(
"UPDATE OLLicenses SET lactive = '1' WHERE cbusno = '{0}'",
Request("cbusno"))
to this:
sqlds2.UpdateCommand = "UPDATE OLLicenses SET lactive = '1' WHERE cbusno = #no")
sqlds2.UpdateCommand.Parameters.AddWithValue("#no", Request("cbusno"))
Next, you'll want to use a different API here:
Sqldatasource1.Clear()
Sqldatasource1.InsertParameters.Add("cbusno", Request("cbusno"))
Sqldatasource1.InsertParameters.Add("licsubcategory", tb5.Text)
Sqldatasource1.InsertParameters.Add("description", tb5.Text)
Sqldatasource1.InsertParameters.Add("nfee", tb2.Text)
Sqldatasource1.InsertParameters.Add("lactive", "0")
Sqldatasource1.InsertParameters.Add("tadded", DateTime.Now.ToString())
Sqldatasource1.InsertParameters.Add("cuserid", Session("Username"))
Sqldatasource1.InsertParameters.Add("myfield", Request("myfield"))
Sqldatasource1.Insert()
This allows the data source to handle the typing for you.
Same as aforementioned with this block:
SqldatasourceFee.InsertParameters.Add("myfield", Request("myfield"))
SqldatasourceFee.InsertParameters.Add("Amount", tb2.Text)
SqldatasourceFee.InsertParameters.Add("CalculatorDescription", (string)clicnotxt.Table(0)(0))
SqldatasourceFee.InsertParameters.Add("Dept", "Business Tax")
SqldatasourceFee.InsertParameters.Add("Module", "Business Tax")
SqldatasourceFee.InsertParameters.Add("Type", tb4.Text)
SqldatasourceFee.InsertParameters.Add("SubType", tb5.Text)
SqldatasourceFee.InsertParameters.Add("Inactive", "0")
SqldatasourceFee.InsertParameters.Add("UserCreated", Session("Username"))
SqldatasourceFee.InsertParameters.Add("Description", Request("cbusno"))
SqldatasourceFee.Insert()
Now, take note to a couple of things. First, notice I casted this value to a string here (string)clicnotxt.Table(0)(0). That value was suspect to me, but I don't believe it's the source of your error. I think the issue here are stuff like this:
SqldatasourceFee.InsertParameters.Add("Inactive", "0")
I'm thinking, but can't be 100% sure, that it should be:
SqldatasourceFee.InsertParameters.Add("Inactive", "False")
Finally, when you build a SqlDataSource inline like this:
Dim sqlds1 As SqlDataSource = New SqlDataSource()
you need to wrap it in a Using because it implements IDisposable:
Using sqlds1 As SqlDataSource = New SqlDataSource()
sqlds1.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings("myconnectionstring").ConnectionString
sqlds1.UpdateCommand = "UPDATE Fees SET Inactive = '1' WHERE Description = #Desc"
sqlds1.UpdateCommand.Parameters.AddWithValue("#Desc", Request("cbusno"))
End Using
The title, while long, pretty much says it all.
What I have is a master table with a bunch of supporting table relations through foreign keys. For a few of the foreign tables, upon attempting to insert a record into the master table where one of the foreign keys doesn't exist, the data would be passed to the foreign table to create the record first, thereby making the constraint valid and passing the key to the created record back to the insert procedure of the master table.
This data comes from a form in String form, but naturally the foreign key will be an int. The process would look something like this:
-- ASP.NET Web Form --
Requestor Name: _____________ (combobox)
Request: _____________ (dropdownlist)
Date: _____________ (datepicker)
This is a super simplified version, but assume we have a master table with the above data, where both names are foreign keys to a People table. The name fields are comboboxes with a populated list of names linking to People. However, if I wanted to enter a person who didn't yet exist in the People table, the procedure should first create the Person, then use the ID from that new record as the foreign key in the Master table containing columns for the above.
I'm using SQL Server and ASP.NET with VB.NET codebehind. I've been scratching my head over this one for awhile, how to pass data (in different forms such as a foreign key or string) between the web server and DB server, as well as where to validate / transform the data.
It seems the entered name will be passed as an ID if the foreign key exists, and a String if not.
This is my most perplexing problem so far, and no idea where else to look. I've read up on Scott Mitchell's site and others.
MY SOLUTION (?)
The best I can come up with is to pass the user input from the user as a string and convert it to int in the T-SQL procedure. If the value was selected from the drop down, it should match precisely with a valid foreign key. If it doesn't match, then create a new Person and return a foreign key. Is this best practice?
This seems complicated because it is. You have to get your hands dirty. If you need a relational database with ACID support, there's no auto-magical way of getting around it.
Relational databases 101: The primary key must exist before the foreign key can be populated (This is the reason why data warehouse developers populate the dimension table before the fact table). You'll have to design the logic to validate that the primary key exists, insert and get the key if not, and just get the key if exists.
Here's my implementation. I don't know if it's the best, but it worked well for me. Basically I take the values from the controls; in the case of the combobox I need the values from both the TextBox and DropDownList. I then pass those values to the following function in my codebehind:
'This method determines if the name selected already exists in the selection
' options and if so assigns the corresponding ID value to an object variable,
' if not it assigns the value of the `TextBox` to the variable.
Protected Function _ValidateValues(ByRef ddl As DropDownList, ByRef cb As TextBox) As Object
'Ensures the selected value is valid by checking against the entered value in the textbox
If Not String.IsNullOrEmpty(cb.Text) Then
If ddl.Items.Count > 0 Then
If StrComp(cb.Text, ddl.SelectedItem.ToString) = 0 Then
Return ddl.Items.Item(ddl.SelectedIndex).Value 'Returns the index of dropdown selected name
End If
End If
'This counts the capital letters in the entered value and if fewer than 2
' auto capitalizes the first letters. This also allows for project code
' names such as "DOORS" and people names such as "Allen McPherson" etc.
' Be careful though because if "allen McPherson" is entered, it will NOT
' be corrected, though it displays correctly.
Dim rg As New Regex("[A-Z]")
Dim mc As MatchCollection = rg.Matches(cb.Text)
If mc.Count < 2 Then
Return StrConv(cb.Text, VbStrConv.ProperCase)
Else : Return cb.Text
End If
End If
'Returns a SQL DB NULL object if an empty string is submitted
Return DBNull.Value
End Function
Then my stored procedure handles the values something like so...
(Forgive me if I neglected to replace some of the values. I tried to catch them all.)
CREATE PROCEDURE spInsertUser
#User nvarchar(50) = NULL,
#Role nvarchar(50) = NULL,
#RecordID int output -- Returned Value
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- CHECK IF USER EXISTS
-- Insert new record to Users table if the requested user doesn't exist
-- Needed to ensure that the foreign keys are relevant
IF #User = '' OR #User IS NULL BEGIN SET #User = NULL SET #RecordID = NULL END --Ensures that an empty string cannot be submitted, thereby causing an error.
ELSE BEGIN
declare #forename varchar(50), #surname varchar(50)
declare #uid table (ID int)
declare #users table (ID smallint, Name nvarchar(50))
insert into #users
select ID, Name from Users
--If the value can be converted into an int, we need go no further.
BEGIN TRY SET #RecordID = CONVERT(smallint, #User) END TRY
BEGIN CATCH
BEGIN TRY --Otherwise, attempt to parse the name
Set #User = LTRIM(RTRIM(#User)) --Trim the extra space at the beginning and end. This ensures the following "IF" test will evaluate properly.
IF NOT CHARINDEX(' ', #User) > LEN(#User) AND CHARINDEX(' ', #User) > 0 BEGIN -- Confirm First & Last Name exist
Set #forename = RTRIM(LEFT(#User, CHARINDEX(' ',#User,0)-1))
Set #surname = LTRIM(RIGHT(#User, LEN(#User) - CHARINDEX(' ',#User,0)))
Set #User = #forename + ' ' + #surname --Ensure that there is a valid First & Last name
IF LEN(#forename) > 1 AND LEN(#surname) > 1 BEGIN -- Confirm First & Last Name exist
--First ensure that the User doesn't already exist, and if
-- so use their ID, if not insert the new User.
IF NOT EXISTS (select Name from #users where Name like #User) BEGIN --Check if the user already exists
INSERT INTO Users (Name, Forename, Surname) OUTPUT INSERTED.ID INTO #uid Values (#User, -- If not, insert them
#forename, #surname) --Nicely manicured first, last, and full names
SET #RecordID = CONVERT(smallint, (select MAX(ID) from #uid)) END -- Now set the Role to the ID of the new user
ELSE BEGIN --Otherwise if the user already exists, set the Role to the ID of that user
SET #RecordID = (select ID from #users where Name like #User) END
IF NOT EXISTS (select * from rUsersInRoles where UserID = #RecordID) BEGIN
--Do some string manipulation to increase the chances of matching the role
SET #Role = REPLACE(REPLACE(REPLACE(LTRIM(RTRIM(#Role)), ' ', '%'), '.', '%'), '#', '%') --Trims & replaces spaces & periods with wildcards
INSERT INTO rUsersInRoles (UserID, UserRoleID) VALUES
(#RecordID, (select top 1 ID from rUserRoles where Role like #Role)) END
END
END
END TRY
BEGIN CATCH END CATCH
END CATCH
END
END
This stored procedure deals with the case of User Roles as well. If the more simple case of Users only is needed, simply remove the clauses dealing with the checking and insertion of User Roles. :)