Grab record ID after inserting the record [duplicate] - c#

This question already has answers here:
How to insert a record and return the newly created ID using a single SqlCommand?
(9 answers)
Return value from SQL Server Insert command using c#
(3 answers)
Closed 9 years ago.
I need to grab the ID of the record so that I can forward the user to another page with the information they just submitted. I looked at other questions regarding this and people suggest using SELECT SCOPE_IDENTITY() or OUTPUT but I'm really new to c# and SQL so I don't know exactly how to use it with my existing code. Any assistance would be greatly appreciated.
You can see I need to put the ID of the record I just inserted in the response.redirect.
pcn.Open();
pcm.Connection = pcn;
string logon_user = Request.ServerVariables["LOGON_USER"].Substring(7);
var sql = String.Format(#"INSERT INTO Transfer (Status, Type, Name) values ('{0}','{1}','{2}')", '0', TypeTxtBox.Text.Replace("'", "''"), logon_user);
pcm.CommandText = sql;
pcm.ExecuteNonQuery();
pcn.Close();
Response.Redirect("View.aspx?ID=" + id);
Yeah, I see that there are other questions similar to this but I'm looking for exact help with my code above, don't mark this duplicate because its NOT!

Firstly read up on parameterised SQL, don't ever use string concatenation for SQL as you are far more likely to fall foul of SQL injection!
To get the ID, you will need to update your code to look like this:
pcm.CommandText = "INSERT INTO Transfer (Status, Type, Name) values (#status, #type, #name);SELECT SCOPE_IDENTITY();";
object identifier = pcm.ExecuteScalar();
if your identifiers are integers, you can cast identifier to an int to get the value (adjust accordingly for Guids etc)
int id = (int)identifier;

SCOPE_IDENTITY gets last identity value inserted into an identity column in the scope.
SqlCommand.ExecuteScalar executes the script and retrieves the ID.
var sql = String.Format(#"INSERT INTO Transfer (Status, Type, Name) values ('{0}','{1}','{2}')
SELECT CAST(scope_identity() AS int)"
, '0', TypeTxtBox.Text.Replace("'", "''"), logon_user);
int ID = (int)pcm.ExecuteScalar();

You will need to use ExecuteScalar instead of ExecuteNonQuery. There are various ways to get the ID, but SCOPE_IDENTITY() is what I would use.
You can see an example on MSDN here:
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.executescalar.aspx

Related

What is purpose of using OleDb Parameters? [duplicate]

This question already has answers here:
When should I use prepared statements?
(4 answers)
Closed 1 year ago.
I have code that inputs data into db using OLEDB. Let's say it looks like this
var commandText = $"INSERT into {tableName}
({columnName1}, {columnName2})
VALUES ({value1, value2});"
var command = new OleDbCommand(commandText, connection);
command.ExecuteNonQuery();
Suggestion is to use OLEDB parameters, something like this
var commandText = $"INSERT into {tableName}
([{columnName1}], [{columnName2}])
VALUES (?, ?);"
var command = new OleDbCommand(commandText, connection);
command.Parameters.Add(new OleDbParameter(columnName1, value1));
command.Parameters.Add(new OleDbParameter(columnName2, value2));
command.ExecuteNonQuery();
What are the benefits of using parameters here?
Does it really improve security if the values are validated before?
With this code, no amount of parameters can help you.
The fact that you're concatenating the table name and the columns names makes your query vulnerable to SQL Injection attacks, which is the primary (but not only) reason to use parameters.
The way SQL injection works is by replacing parts of the string sent to the database with sql code. Parameters prevent that from happening because the database treats them as placeholders for data, which means it will not run any sql code that was passed through them.
However, since your table name and column names are also c# variables, they can be replaced with SQL code that the database will try to run.
Suppose the following code:
var tableName = "table (Col1) VALUES (null);DROP TABLE table;--";
// declare and populate columnName1, columnName2 with whatever values you want here, even just nulls
var commandText = $"INSERT into {tableName}
([{columnName1}], [{columnName2}])
VALUES (?, ?);"
// run SQL command here
This will insert a single record into table, and then drop the table from the database.
For more information, read my blog post entitled Back to basics: SQL Injection
Actually, yes. We all make mistakes and the extra safety added by the parameter object is like a second set of eyes.
Also, if you always use the parameter object, you run less of a risk in introducing errors down the line.

SQL IN Clause issue when comparing values [duplicate]

This question already has answers here:
Parse comma-separated string to make IN List of strings in the Where clause
(4 answers)
Closed 2 years ago.
I have the below column in table x where SharedBagsIds contains the string (1,3,4)
I am trying to write an SQL query that contains the in clause as follow
select * from .... where id in (x.SharedBagsIds)
but this line id in (x.SharedBagsIds) is generating an error
Conversion failed when converting the varchar value '1,3,4' to data type int.
is there a way to fix this issue?
This is not how the IN clause is used and you're comparing an integer (your id) to a string ('1,3,4'). You'll need to split the column value into multiple values, then check if the id matches any of the values:
WHERE (',' + RTRIM(SharedBagsIds) + ',') LIKE '%,' + #id + ',%'
See this answer.
Or consider extracting SharedBagsIds into its own table, storing comma-delimited values in a database field is not ideal.
Your table is not in 1st normal form which states that every cell should be atomic. 'SharedBagsIds' contains more than one value which should always be avoided. Read about many to many relationships in SQL and modify the table accordingly.
Suppose I have table Teacher and another table student, then to show the relationship between them, create another table which contains teacherid and studentid as the composite primary key. Thus you can show individual mapping without having the need to put multiple ids like 1,3,4 in single cell.
Hope this helps.

WPF C# insert to mysql AddWithValue

I have an insert statement
command.CommandText = " insert into system (ziel, comment, status,art) values (#eort,#comment,#statebox,#Eart) ";
Behind statebox is a Combobox. Every word which can be chosen in the Combobox is created as a tablerow in my database.
the values are created here:
command.Parameters.AddWithValue("#eort",textBo3x.Text);
command.Parameters.AddWithValue("#comment", textBox_Copy1.Text);
command.Parameters.AddWithValue("#statebox", MyComboBox.Text);
command.Parameters.AddWithValue("#Eart", MyComboBox_Copy1.Text);
command.Parameters.AddWithValue("#thetime", thetime_insert.Text);
This works.
But I want to use the #values in the insert Statement like this:
command.CommandText = " insert into els (ziel, #statebox,comment,status,Eart) values (#eort,#thetime,#comment,#statebox,#Eart) ";
This gives me an mysql error.
It seems that the #values have '' at the words.
How can i delete this?
Your INSERT statement as pointed below is wrong. You can't simply plug-in a dynamic column in your insert statement which doesn't exists in your table schema
insert into system (ziel, #statebox,comment,status,Eart)
This can only be done in case of SELECT statement and doing below is perfectly alright
select ziel, #statebox,comment,status,Eart from `system`
Well, if you have your column name in variable then build your query string like
string query = string.Format("insert into els (ziel, {0},comment,status,Eart) values ", column_name_variable);
You cannot use a parameter to reference a field name. However, if you provide your user with a predetermined list of fields between he/she can choose then you can safely use a form of string concatenation to insert the field to update/insert into.
This means that you need to have a combobox without any editing capability but just a selection of the possible fields.
In your case, it seems that this combobox could be the one named MyComboBox
Thus
command.CommandText = #"insert into els
(ziel, " + MyComboBox.SelectedItem.ToString() +
#",comment,status,Eart) values
(#eort,#thetime,#comment,#statebox,#Eart)";
Said that consider to remove the use of AddWithValue. This shortcuts has big drawbacks, in particular when you pass a string variable (Text) and expects it to correctly translate your text in a datetime value.
Use the Add method instead converting and checking your inputs and specifying the correct datetype for the parameter.
DateTime dt;
if(!DateTime.TryParse(thetime_insert.Text, out dt);
// Message, not a valid date....
else
command.Parameters.Add("#thetime", MySqlDbType.Date).Value = dt;

Cast uniqueidentifier to string and use in Where clause

figured out answer and edited question so it works now.
Here is my example
CustomerID column in my database is set to uniqueidentifier.
C#
string cid = ( This is a variable; it could be ANY guid the user chooses. )
Query String
" SELECT * FROM [db]
WHERE (CAST(CustomerID AS VARCHAR(100)) LIKE '%"+cid+#"%');"
The CustomerID field does not evaluate for a rows with the same cid. So the cid is having trouble being evaluated with the uniqueidentifier (CustomerID).
Don't build your query by string concatenating user input into the query. It can lead to sql injection which is a serious issue.
Instead you should use parametrized queries, where you pass the user input to the query in the form of a parameter. The underlying framework/driver/etc will then make sure that the user input is prepared in a way that cannot accidentally become sql code.
Something like this:
Guid cidAsGuid = new Guid(cid);
MySqlCommand command = new MySqlCommand("SELECT * FROM [db] WHERE CustomerId = #customerID");
command.Parameters.AddWithValue("#customerID", cidAsGuid);
And then you can use the command to execute a reader or fill an adapter or some other thing you need to do.
This has the added benefit that an index on the CustomerId column can be used to speed up the query, whereas if you search by converting the CustomerId from a Guid to a string means the database will have to scan the whole table. For small tables you won't notice much difference but for large tables the difference will be significant.
I'm seeing a few possible issues;
There's no condition defined for the ISNULL e.g. ISNULL(Column,valueifnull).
Also the actual query must specify a column to use ISNULL in that structure.
There's a missing "closing bracket" on the ISNULL.
Something such as this should work:
SELECT ISNULL(
(
SELECT Column1 FROM MyTable
WHERE (CAST(CustomerID AS VARCHAR(100)LIKE '%"+cid+#"%')
)
,'')
You don't need like if CustomerID is uniqueidentifier too.
WHERE (CAST(CustomerID AS VARCHAR(36)) = #cid)

How can I get the GUID value of a new row after inserting it? [duplicate]

This question already has answers here:
Best way to get PK Guid of inserted row
(2 answers)
Closed 9 years ago.
I am trying to get the Id of newly inserted record in Sqlserver. I have checked the Scope_Identity() but this is said to return the value of the autoincrement column. The column I am using for Id is Guid. I want this Guid column value after the insert. How should this be achieved? Or I must have to write a custom tedious function to get the Id of newly inserted record.
You can try and use OUTPUT, it would be something like:
INSERT INTO ExampleTable (<Column1>, <Column2>, <Column3>)
OUTPUT INSERTED.ID
VALUES (<Value1>, <Value2>, <Value3>)
Also, this question, has a lot more info on the different types of identity selection, you should check it out.
EDIT
You would use this as a regular scalar:
var command = new SqlCommand("...");
Guid id = (Guid) command.ExecuteScalar();

Categories