So I am working on modifying an existing query in classic ASP. Classic ASP is fairly new to me, especially this ADODB Command stuff.
As it says on Microsoft's Docs
Name
Optional. A String value that contains the name of the Parameter object.
While the other stuff is also nothing I'm familiar with, those are questions for another day.
sql = "INSERT INTO Paintings (pieceName, artistName, description, galleryID) VALUES (?, ?, ?, ?)"
set sqlCmd = Server.CreateObjects("ADODB.Command")
sqlCmd.Parameters.Append(sqlCmd.CreateParameter("#PieceName",adVarChar,adParamInput, 256, txtPieceName))
sqlCmd.Parameters.Append(sqlCmd.CreateParameter("#ArtistName",adVarChar,adParamInput, 256, txtArtist))
sqlCmd.Parameters.Append(sqlCmd.CreateParameter("#Description",adVarChar,adParamInput, 5000, txtDescription))
sqlCmd.Parameters.Append(sqlCmd.CreateParameter("#Description",adInteger,adParamInput, 256, txtGalleryID))
ADODBCon.query(sql, sqlCmd)
Point is, the code is from their live branch. I can see that #Description doesn't match the SQL, so I can figure the command is either case insensitive or the name argument isn't related to the SQL at all.
Second, #Description is used twice and still works, with two different types. I know it says optional, but if it does not relate to the SQL, and can exist by the same name with different types, is it just for readability?
I'm sorry if A String value that contains the name of the Parameter object completely explains its purpose and I'm just not getting it, but what is the purpose of the name argument?
The CreateParameter method is actually creating a Parameter object which the .Append method then adds to the ADODB.Command object's, sqlCmd in this case, Parameters collection. Since it is a collection, the name is optional as a collection item can be accessed by item index.
From the documentation on Parameter Name property:
For Parameter objects not yet appended to the Parameters collection, the Name
property is read/write. For appended Parameter objects and all other objects,
the Name property is read-only. Names do not have to be unique within a
collection.
Related
I am debugging an application that runs on a server and users will access the application on another server. The application uses encryption and as part of the key, I am using the String.Reverse property.
Dim Mystring As String = "123abc"
Dim reverse = String.Format("{0},{1}", Mystring.Reverse)
The string reverse is different when I run it from one machine (RDP/Citrix Environment ASP.NET 4.6.1). The value is:
System.Linq.Enumerable+<ReverseIterator>d__a2`1[System.Char]
The same string, but ran from another machine (RPD non-Citrix Environment ASP.NET 4.5.2). The value of reverse is:
System.Linq.Enumerable+<ReverseIterator>d__73`1[System.Char]
Why are the values different in the different environments?
Look at this line first:
Dim reverse = String.Format("{0},{1}", Mystring.Reverse)
Specifically, this expression:
Mystring.Reverse
Reverse is a function, not a property, but it's missing the parentheses (). The trick here is the String.Format() method accepts the base Object type as an argument, and compiler is able to treat the MyString.Reverse expression as a delegate type that is convertible to object. The values you see in your output are the result of calling .ToString() on that function delegate. It's the type name for the function, rather than anything to do with the value of your MyString object. Since that type is dynamically and randomly generated at runtime, you'll see different values not only on different platforms, but different runs on the same computer.
In the VB6 era, it was normal to call methods without the parentheses. In the .Net world, always use parentheses when you call a method.
What you want is this:
Dim reverse As String = String.Format("{0},{1}", Mystring.Reverse())
Even here, you're missing the second argument to match the format string. I doubt you'll get the result you expect.
Finally, reversing a string as the key seems very wrong when it comes to encryption. You are using a real cyrptogrpahic algorithm from the System.Security.Cryptography library, right? Right!?
You are not outputting the value of the reversed String but the name of the type used to perform the reversal. That type is dynamically created and randomly named. The "d" in those two names means "dynamic" and the "a2" and "73" parts are random.
Basically, what you perceive to be an issue is not an issue. The problem is that you're not actually creating a String from the reversed output. You say "String.Reverse property but that is NOT a property. It is a method and it is not a member of the String class but rather an extension method on the IEnumerable(Of T) interface. You are treating your String as an enumerable list of Char values and reversing that. If you want a String from that then you need to create one, i.e.
MyReversedString = New String(Mystring.Reverse().ToArray())
That will push the contents of your iterator into an array and then create a new String object from that array.
I'm using Entity Framework to send a query to the database using ExecuteStoreQuery
If (DBEntity.ExecuteStoreQuery(Of Integer)("SELECT COUNT(ReceiptUID) FROM qryRptSrc_Cust_GoodsReceipt_Issues WHERE ReceiptUID = #Recpt", ReceiptUID)(0) > 0) Then ....
Which gives me the error message that my scalar variable #Recpt hasn't been declared. I know what that error message means, but I'm wondering why it's being thrown in this case. ReceiptUID is a Guid with the correct value. The parameters that are passed don't have to be DbParameter objects, they can just be values and it should work fine. I've done it that was in the past before without issue, and even MSDN states
The parameters value can be an array of DbParameter objects or an array of parameter values. If only values are supplied, an array of DbParameter objects are created based on the order of the values in the array.
I could create a DbParameter object instead, but I'd like to know why this case isn't working.
Token answer:
Try #p0 instead of #Recpt
Edited to answer my own question. This appears to be a LINQ/VB bug.
A simple LINQ query returning an anomymous type will sometimes change the field names specified in the query so as to capitalize them. Perhaps passing the result of the query as a parameter to a method call:
someThing.someMethod(From someStuff In stuffList _
Select text = someStuff.Name(), _
value = someStuff.Id
)
where someMethod has signature
Public Sub someMethod(ByVal list As IEnumerable(Of Object))
If you step into the execution of someMethod, and then examine the value of list in quickwatch, you may or see the field names as "text"&"value" or "Text"&"Value".
LINQ queries should not be changing the field names as specified in the query, so the correct behavior is fieldnames "text"&"value". Yet production builds of our application have the incorrect capitalization behavior (which can be determined indirectly), and debug builds have shown it both happening both ways at different times and/or for different developers' machines.
I've looked high & low for some feature of LINQ which controls this behavior, but now am virtually certain it is a bug. (msdn forum thread, MS Connect bug page)
This is likely to only cause a problem if you are using reflection, such as type.getfield() such as in
listItem = list.ElementAt(index)
itemTextField = listItem.GetType().GetField("text")
itemText = CType(itemTextField.GetValue(listItem),String)
If this happens to you, the workaround is to use overload of GetField with bindingflags to make it case-insensitive:
itemTextField = listItem.GetType().GetField("text", BindingFlags.IgnoreCase)
It must be pretty rare to encounter this bug, but maybe the next person will spend less time scratching their head if they find this info here.
=========original post===========
Getting different behavior in my debug build environment than in my coworkers' and our production envirnonment, relating to LINQ and reflection...
While running debug build of legacy code, the following code
Dim objectType As Type = obj.GetType()
Dim field As FieldInfo = objectType.GetField(name)
Dim prop As PropertyInfo = objectType.GetProperty(name)
results in Nothing for field & prop.
The value of obj is passed down from above and is the result of a LINQ query (it is a single element of the list generated by the query):
From bpt In CustomBProcessTypes Select text = bpt.Name(), value = bpt.Id
The value of name is also passed from above and is "Text" (note capitalization).
I can examine obj in the debugger and confirm that the fieldnames of the object created by the LINQ query are 'text' and 'value' (note lack of capitalization) which is what I would expect.
So failure to find the field by the capitalized name makes sense. However, our production builds and my coworkers builds do not have this problem.
Because calls to type.getfield(string) are expressly cas-sensitive, the only thing I can think of at this point is there must be some configuration of LINQ relating to auto-capitalization of column/fieldnames, and my environment is not set up the same as the others.
Using visual studio 2012. I don't know much of anything about LINQ, per se.
Anyone have any idea what could be going on here?
(NOTE: if I can get an opportunity, I'll have a coworker step through the relevant code and see if in their environment the object created by the linq query ends up with capitalized field names)
EDIT: I verified with a coworker in his debug build: his LINQ query creates a list of objects with field names "Text" and "Value", but on in my environment the LINQ query ends up with field names "text" and "value". The code is the same, but there must be something about how LINQ is configured in my environment which fails to auto-capitalize those field names, but which happens on their machines and in our production environment.
I suppose it is possible that some compiler settings are resulting in different capitalization. Normally this would make no difference because VB.NET is a case-insensitive language so obj.Text and obj.text both work just as well. But to use case insensitivity in reflection lookups, you need to specify it by including BindingFlags.IgnoreCase in the second parameter of GetField or GetProperty:
Dim field As FieldInfo = objectType.GetField(name,
BindingFlags.Public Or BindingFlags.Instance Or BindingFlags.IgnoreCase)
I'm confused as to where name is coming from, though. Some other code is getting the field name from reflection on the query? I didn't see where this was explained in your question.
I have answered my own question (insofar as is possible). Boils down to a bug in LINQ/vb.net.
Fully explained at top of original post (edited in). Hope this saves someone time in the future.
In one of our application the parameters passed to a stored procedure in this way
Dim parm As New SqlParameter("searchText", SqlDbType.VarChar)
parm.Direction = ParameterDirection.Input
parm.Size = 50
parm.Value="test"
cmd.Parameters.Add(parm)
and the procedure contains a parameter as #searchText
i.e. the parameter name passed from the code is searchText and that in the stored procedure is #searchText .
But it is working properly, I am always getting the required results.
So my question is like so there is no need to specify # before the parameter? Whether it will append #, can anyone please give an answer for this.
According to the documentation, the name must start with an #:
The ParameterName is specified in the form #paramname.
According to the source code (have a look at SqlCommand and SqlParameter.ParameterNameFixed in the reference source), an # is added automatically, if needed.
So yes, it works, but it's an undocumented feature. Best practice recommends that you do not rely on this and manually prefix your parameter name with an #.
Ref: SqlParameter.ParameterName Property and IDataParameter.ParameterName Property
The ParameterName is specified in the form #paramname. You must set ParameterName before executing a SqlCommand that relies on parameters. If you are using Sql Server as Database then you must specify # before
the parameter name.
your parameter name must be same as at backend eg. you have #searchText then in your parameter specification it must be SqlParameter("#searchText" ..
your code should be like this
Dim parm As New SqlParameter("#searchText", SqlDbType.VarChar)
parm.Direction = ParameterDirection.Input
parm.Size = 50
parm.Value="test"
cmd.Parameters.Add(parm)
Note: Oracle and SqLite use different use different character to specify parameter and there may be # symbol is not used specified by the specification of ado.net.
Edit: By comments
As you specified the link, it is also some sort of fix, but as per the msdn documentation, you must specify the positional parameter with '#' whether you are using any data provider oledb, sql, odbc. Ref
if (0 < parameterName.get_Length() && '#' != parameterName.get_Chars(0))
{
parameterName = "#" + parameterName;
}
Its not compulsory to specify the #. However, its a best practice.
Its similar in analogy to strings. There certainly is no harm in defining strings as such in .NET:
string s;
//Rest of the code follows;
But again, its a best practice to define them as :
string s = string.Empty;
You see, its a question of conventions and best practices!!!
I recommended you to use add "#" marker with your parameter name.
SqlParameter helps to add automatically, but others' parameter might not to.
Is the "#" symbol required? Yes and No. When you add a parameter using DbCommand, it's optional regardless of whether you're using SQL Server or not:
// Look Ma no # required!
DbCommand command = database.GetStoredProcCommand("StoredProctologistAndGambler");
database.AddInParameter(command, "Bet", DbType.Int32, fromLineNumber);
database.AddOutParameter(command, "Diagnosis", DbType.String, -1);
If you're going to reference the command later, however, the "#" prefix is required. Microsoft figured it was to hard to carry it over to the rest of the API.
var examResult = command.Parameters["#Diagnosis"]; // Ma! Microsoft lied! It requires the "#" prefix.
I have an EntityA which has an optional attribute int32 result. When I create EntityA I do not set the result attribute. Then later on when I fetch it I expect it to have nil value but for some reason it's set to 3 even though I have not set this attribute.
What's going on here?
1st possible issue:
You have set a default value in the model editor. Select the attribute and check the inspector.
2nd possible issue:
You are retrieving or showing the wrong value. Show the code you are using to find out that result is '3'.
3rd possible issue:
You are setting the value later inadvertently, perhaps in a loop or something similar. Do a text search for the attribute to find a possible occurrence in your code.
Your int32 will be stored wrapped into a NSNumber object. If you don't provide a value, no NSNumber object will be created - sql will treat it as NULL.
The iOS Core Data Programming Guide says:
You can specify that an attribute is optional—that is, it is not
required to have a value. In general, however, you are discouraged
from doing so—especially for numeric values (typically you can get
better results using a mandatory attribute with a default value—in the
model—of 0). The reason for this is that SQL has special comparison
behavior for NULL that is unlike Objective-C's nil. NULL in a database
is not the same as 0, and searches for 0 will not match columns with
NULL.
So, it may be better to either make the attribute mandatory and set it to a distinct value, or to pass in NSNumber from the start.