Special character not saved in MS SQL - c#

I have a small problem with this Czech character ů. This little bugger won't save into my MS SQL table when the update is triggered from my C# code.
If I manually add it in SQL Management Studio it is saved as it should, and it is also shown on the website as normal.
But the process of saving it from C# only ends in the character u beeing saved in the table and not ů.
My DB fields are of type nvarchar and ntext and the collation of the DB is French_CI_AS. I'm using MSSQL 2008.
Code:
SqlCommand sqlcomLoggedIn = new SqlCommand("UPDATE Table SET id = 1, title = 'Title with ů' WHERE id = 1", sqlCon, sqlTrans);
int status = sqlcomLoggedIn.ExecuteNonQuery();
Any thoughts?

The immediate problem is that you aren't using a unicode literal; it would have to be:
UPDATE Table SET id = 1, title = N'Title with ů' WHERE id = 1
the N is important.
The much bigger issue is that you should be using parameters:
int id = 1;
string title = "Title with ů";
// ^^ probably coming from C# parameters
using(var sqlcomLoggedIn = new SqlCommand(
"UPDATE Table SET title = #title WHERE id = #id", sqlCon, sqlTrans))
{
sqlcomLoggedIn.Parameters.AddWithValue("id", id);
sqlcomLoggedIn.Parameters.AddWithValue("title", title);
int status = sqlcomLoggedIn.ExecuteNonQuery();
}
then the problem goes away, you get to use cached query plans, and you avoid sql injection

Related

Trying to insert a proper string value in parameterized query using Odbc and MySQL results in empty string in database

I'm trying to use parameterized queries in C# for my job assignment as it seems to be the correct way to guard against SQL injections and simplify code.
When the INSERT command is executed the row is inserted otherwise correctly except the string/varchar column is empty.
I attached the minimum code necessary below. Database column types are as follows:
id_number = int(11), datetime_now = datetime, some_text = varchar(64).
The code is running on Ubuntu 14.04.6 LTS and connecting to local database MySQL 15.1 Distrib 5.5.64-MariaDB. The driver is /usr/lib/x86_64-linux-gnu/odbc/libmyodbc.so.
I could only find one example online of this exact problem (no answers):
String Parameters not working when using MySql over Odbc
I've been stuck with this for a couple of days now and I'm getting desperate. I don't know how to proceed except abandoning parameterized queries completely. I've tried different overloads of the OdbcParameterCollection.Add() method as well as AddWithValue(), still the results are incorrect. Is it possible there is a problem with the ODBC driver itself?
OdbcCommand command = conn.CreateCommand();
command.CommandText = "INSERT INTO MyTable (id_number, datetime_now, some_text) VALUES (?, UTC_TIMESTAMP(), ?)";
command.Parameters.Add("#id_number", OdbcType.Int).Value = 1;
command.Parameters.Add("#some_text", OdbcType.VarChar).Value = "Example text";
conn.Open();
command.ExecuteNonQuery();
I would expect that the row would be inserted correctly or an error would be given.
Instead the inserted row has
id_number = 1, datetime_now = 2019-08-22 14:05:19, some_text = "".
Edit. Changed code: added "#" to parameter names to exactly follow accepted answers in: How to bind parameters via ODBC C#?. The problem still persists.
Edit2. Added datatable code and information about the connection string.
Database table code is:
MariaDB [myDB]> SHOW CREATE TABLE MyTable;
+---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| MyTable | CREATE TABLE `MyTable` (
`id_number` int(11) NOT NULL AUTO_INCREMENT,
`datetime_now` datetime NOT NULL,
`some_text` varchar(64) NOT NULL,
PRIMARY KEY (`id_number`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1 |
+---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
The connection string uses DSN, so it is:
connString = "DSN=myodbc-mydb;";
/etc/odbc.ini:
[myodbc-mydb]
Driver = myodbc_mysql
Description = myODBC
SERVER = 192.168.24.25
PORT = 53769
USER = myUser
Password = myPassword
Database = myDB
OPTION = 3
SOCKET =
/etc/odbcinst.ini:
[myodbc_mysql]
Description = ODBC for MySQL
Driver = /usr/lib/x86_64-linux-gnu/odbc/libmyodbc.so
Setup = /usr/lib/x86_64-linux-gnu/odbc/libodbcmyS.so
UsageCount = 8
Threading = 0

Inserting a value into a sql database by using a sql query

This is my first row where I create a track (THIS WORKS)
String TrackAdd = "INSERT INTO Track (Titel) VALUES (#Titel)";
using (SqlCommand sqlCmd = new SqlCommand(TrackAdd, connection))
{
sqlCmd.Parameters.AddWithValue("#Titel", textBoxTitel.Text);
sqlCmd.ExecuteNonQuery();
}
Then I want to use the ID which was just created for this Track, I need it so I can link it to something else (in this case a genre. I have specified the names for genres in a different table and need their IDs)
I'm now trying this but its not working and I don't really know what to do.
using (var connection = Database.connection)
{
String Track1Genre = "INSERT INTO TrackGenre (TrackId, GenreId) VALUES (#TrackId, #GenreId)";
string Genre = listBoxGenre.GetItemText(listBoxGenre.SelectedItem);
using (SqlCommand sqlCmd = new SqlCommand(Track1Genre, connection))
{
sqlCmd.Parameters.AddWithValue("#TrackId", "Select Id from Track WHERE Titel = textBoxTitel.Text");
sqlCmd.Parameters.AddWithValue("#GenreId", "Select Id from Genre where Genre = Genre");
sqlCmd.ExecuteNonQuery();
}
}
NOTE: There's nothing wrong with the connection or anything, I just need help how to get the ID's out of the database and insert them into a different table
Two ways to do it:
Output Inserted.Id
INSERT INTO Track (Titel) VALUES output INSERTED.ID (#Titel)
and in C#, use:
int lastId =(int)cmd.ExecuteScalar();
Identity_Insert On
SET IDENTITY_INSERT dbo.Track ON;
INSERT INTO Track (Id, Titel) VALUES (1, #Titel)
SET IDENTITY_INSERT dbo.Track OFF;
In this method you already know what Id you are inserting so you can just use this to update your TrackGenre table. But, yes, you have to track your Ids or may be before executing check for last id using select max(id) from Track
You're close. You can't inject SQL the way you intended. You have to move that your insert statement so the query will do a select for each value based on your parameters.
Let's try to workout what the SQL query that gets executed will look like, when you start with this:
String Track1Genre = "INSERT INTO TrackGenre (TrackId, GenreId) VALUES (#TrackId, #GenreId)";
sqlCmd.Parameters.AddWithValue("#TrackId", "Select Id from Track WHERE Titel = textBoxTitel.Text");
sqlCmd.Parameters.AddWithValue("#GenreId", "Select Id from Genre where Genre = Genre");
Remember that whatever (string) value is set on a parameter will be used, without any evaluation. So the above statement will lead to this sql being executed:
INSERT INTO TrackGenre (TrackId, GenreId)
VALUES ('Select Id from Track WHERE Titel = textBoxTitel.Text',
'Select Id from Genre where Genre = Genre');
So it nicely did prevent a SqlInjection attack but it didn't return Id's to tables Track and Genre either, in fact it would bark about a conversion failed to data type int.
Instead you can pass the selection parameters as is and then use those in the queries to get the id's of the rows you're interested in.
Staying as close as possible to what you currently have, this would work:
using (var connection = Database.connection)
{
String Track1Genre = #"
INSERT
INTO TrackGenre(TrackId, GenreId)
VALUES (
(SELECT id FROM track WHERE titel = #titel), /* do a select for the ID */
(SELECT id FROM genre WHERE genre = #genre))";
string Genre = listBoxGenre.GetItemText(listBoxGenre.SelectedItem);
using (SqlCommand sqlCmd = new SqlCommand(Track1Genre, connection))
{
// caution, better use Add, see the note
sqlCmd.Parameters.AddWithValue("#titel", textBoxTitel.Text);
sqlCmd.Parameters.AddWithValue("#Genre", Genre);
sqlCmd.ExecuteNonQuery();
}
}
Keep in mind that the insert statement will fail if you have tracks with the same title, or genre's with same name. But that is up to you to handle or prevent from happening upstream.
If you want to be 100% sure that the Id you get from the insert of Track, refer to the Output Inserted.Id option in the answer of Sunil. You'll have to bring the lastid variable over to the code I've shown here, replacing the first parameter with it (and adapt the insert query accordingly).
Note
There is a potential issue with the use of AddWithValue as explained in this blogpost from JCoohorn: https://blogs.msmvps.com/jcoehoorn/blog/2014/05/12/can-we-stop-using-addwithvalue-already/
It is better to prevent the SqlParameter class guess your type wrong. Consider to use
sqlCmd.Parameters.Add("#titel", SqlDbType.NVarChar, 250).Value = textBoxTitel.Text;
instead.
If you want to experiment with the insert query first to get the feel what it is doing, fork this SEDE query.
I dont know if it is a typo or genuine mistake which should be corrected
this line from your code
sqlCmd.Parameters.AddWithValue("#TrackId", "Select Id from Track WHERE Titel = textBoxTitel.Text");
should be written like this
sqlCmd.Parameters.AddWithValue("#TrackId", "Select Id from Track WHERE Titel = " + textBoxTitel.Text);
same problem is with Genre tooo. if your code written is correct then your query is actually searching for 'textBoxTitel.Text' instead of trackid

Error from SQL query

Currently I'm working on cleaning up some code on the backend of an application I'm contracted for maintenance to. I ran across a method where a call is being made to the DB via Oracle Data Reader. After examining the SQL, I realized it was not necessary to make the call to open up Oracle Data Reader seeing how the object being loaded up was already within the Context of our Entity Framework. I changed the code to follow use of the Entity Model instead. Below are the changes I made.
Original code
var POCs = new List<TBLPOC>();
Context.Database.Connection.Open();
var cmd = (OracleCommand)Context.Database.Connection.CreateCommand();
OracleDataReader reader;
var SQL = string.Empty;
if (IsAssociate == 0)
SQL = #"SELECT tblPOC.cntPOC,INITCAP(strLastName),INITCAP(strFirstName)
FROM tblPOC,tblParcelToPOC
WHERE tblParcelToPOC.cntPOC = tblPOC.cntPOC AND
tblParcelToPOC.cntAsOf = 0 AND
tblParcelToPOC.cntParcel = " + cntParcel + " ORDER BY INITCAP(strLastName)";
else
SQL = #"SELECT cntPOC,INITCAP(strLastName),INITCAP(strFirstName)
FROM tblPOC
WHERE tblPOC.cntPOC NOT IN ( SELECT cntPOC
FROM tblParcelToPOC
WHERE cntParcel = " + cntParcel + #"
AND cntAsOf = 0 )
AND tblPOC.ysnActive = 1 ORDER BY INITCAP(strLastName)";
cmd.CommandText = SQL;
cmd.CommandType = CommandType.Text;
using (reader = cmd.ExecuteReader())
{
while (reader.Read())
{
POCs.Add(new TBLPOC { CNTPOC = (decimal)reader[0],
STRLASTNAME = reader[1].ToString(),
STRFIRSTNAME = reader[2].ToString() });
}
}
Context.Database.Connection.Close();
return POCs;
Replacement code
var sql = string.Empty;
if (IsAssociate == 0)
sql = string.Format(#"SELECT tblPOC.cntPOC,INITCAP(strLastName),INITCAP(strFirstName)
FROM tblPOC,tblParcelToPOC
WHERE tblParcelToPOC.cntPOC = tblPOC.cntPOC
AND tblParcelToPOC.cntAsOf = 0
AND tblParcelToPOC.cntParcel = {0}
ORDER BY INITCAP(strLastName)",
cntParcel);
else
sql = string.Format(#"SELECT cntPOC,INITCAP(strLastName), INITCAP(strFirstName)
FROM tblPOC
WHERE tblPOC.cntPOC NOT IN (SELECT cntPOC
FROM tblParcelToPOC
WHERE cntParcel = {0}
AND cntAsOf = 0)
AND tblPOC.ysnActive = 1
ORDER BY INITCAP(strLastName)",
cntParcel);
return Context.Database.SqlQuery<TBLPOC>(sql, "0").ToList<TBLPOC>();
The issue I'm having right now is when the replacement code is executed, I get the following error:
The data reader is incompatible with the specified 'TBLPOC'. A member of the type 'CNTPOCORGANIZATION', does not have a corresponding column in the data reader with the same name.
The field cntPOCOrganization does exist within tblPOC, as well as within the TBLPOC Entity. cntPOCOrganization is a nullable decimal (don't ask why decimal, I myself don't get why the previous contractors used decimals versus ints for identifiers...). However, in the past code and the newer code, there is no need to fill that field. I'm confused on why it is errors out on that particular field.
If anyone has any insight, I would truly appreciate it. Thanks.
EDIT: So after thinking on it a bit more and doing some research, I think I know what the issue is. In the Entity Model for TBLPOC, the cntPOCOrganization field is null, however, there is an object tied to this Entity Model called TBLPOCORGANIZATION. I'm pondering if it's trying to fill it. It too has cntPOCOrganization within itself and I'm guessing that maybe it is trying to fill itself and is what is causing the issue.
That maybe possibly why the previous contractor wrote the Oracle Command versus run it through the Entity Framework. I'm going to revert back for time being (on a deadline and really don't want to play too long with it). Thanks!
This error is issued when your EF entity model does not match the query result. If you post your entity model you are trying to fetch this in, the SQL can be fixed. In general you need to use:
sql = string.Format(#"SELECT tblPOC.cntPOC AS <your_EF_model_property_name_here>,INITCAP(strLastName) AS <your_EF_model_property_name_here>,INITCAP(strFirstName) AS <your_EF_model_property_name_here>
FROM tblPOC,tblParcelToPOC
WHERE tblParcelToPOC.cntPOC = tblPOC.cntPOC
AND tblParcelToPOC.cntAsOf = 0
AND tblParcelToPOC.cntParcel = {0}
ORDER BY INITCAP(strLastName)",
cntParcel);

ODAC seems to be caching table schema?

I'm using Oracle's ODAC.NET for a .NET 3.5 project against an Oracle 11 Express database, and I'm seeing behavior that I can't explain (and can't seem to work around).
ODAC should be the latest, I just pulled it 3 days ago, but the versions are as follows:
Oracle.DataAccess.dll version 2.112.3.0 (release 5)
oci.dll (instant client) version 11.2.0.1
I have a Table, People, that has 3 columns:
ID
FirstName
LastName
In code I run an ALTER TABLE command, using OracleCommand.ExecuteNonQuery, to add a new column named "MIDDLE_NAME" to the table. That command succeeds. If I look at the table with Oracle SQL Developer, the columns shows up. All well and good.
Now if I run use OracleCommand.ExecuteReader with a command text of SELECT * FROM People right after I do the alter table, I get back data with only 3 columns, not 4!
Here is code that reproduces the problem:
public void FieldTest()
{
var sql1 = "CREATE TABLE People (" +
"ID NUMBER PRIMARY KEY, " +
"FirstName NVARCHAR2 (200), " +
"LastName NVARCHAR2 (200) NOT NULL)";
var sql2 = "ALTER TABLE People " +
"ADD Middle_Name NUMBER";
var sql3 = "SELECT * FROM People";
var sql4 = "SELECT column_name FROM all_tab_cols WHERE table_name = 'PEOPLE'";
var cnInfo = new OracleConnectionInfo("192.168.10.246", 1521, "XE", "system", "password");
var connectionString = BuildConnectionString(cnInfo);
using (var connection = new OracleConnection(connectionString))
{
connection.Open();
using (var create = new OracleCommand(sql1, connection))
{
create.ExecuteNonQuery();
}
using (var get = new OracleCommand(sql3, connection))
{
using (var reader = get.ExecuteReader())
{
Debug.WriteLine("Columns: " + reader.FieldCount);
// outputs 3, which is right
}
}
using (var alter = new OracleCommand(sql2, connection))
{
alter.ExecuteNonQuery();
}
using (var get = new OracleCommand(sql3, connection))
{
using (var reader = get.ExecuteReader())
{
Debug.WriteLine("Columns: " + reader.FieldCount);
// outputs 3, which is *wrong* <---- Here's the problem
}
}
using (var cols = new OracleCommand(sql4, connection))
{
using (var reader = cols.ExecuteReader())
{
int count = 0;
while (reader.Read())
{
count++;
Debug.WriteLine("Col: " + reader.GetString(0));
}
Debug.WriteLine("Columns: " + count.ToString());
// outputs 4, which is right
}
}
}
}
I've tried some things to prevent the behavior, and none of them give me back the 4th column:
I close the connection and re-open it
I use a new OracleConnection for the SELECT than for the ALTER
I use the same OracleConnection for the SELECT and for the ALTER
I use a new OracleCommand for the SELECT than for the ALTER
I use the same OracleCommand for the SELECT and for the ALTER
I call PurgeStatementCache on the connection between the ALTER and SELECT
I call FlushCache on the connection between the ALTER and SELECT
I explicitly Close and Dispose the OracleCommand and OracleConnection (as opposed to the using block) used for the ALTER and SELECT
Restarted the calling PC and the PC hosting the Oracle database.
If I look at the column list by doing a SELECT * FROM all_tab_cols, the new column is there.
The only thing that seems to work reliably is closing the app and re-starting it (well it's from a unit test, but it's a shutdown and restart of the test host). Then I get that 4th column. Sometimes I can use breakpoints and re-execute queries and the 4th column will appear, but nothing that is specifically repeatable with straight execution of code (meaning without setting a break point and moving the execution point back up).
Something in the bowels of ODAC seems to be caching the schema of that table, but I can figure out what, why or how to prevent it. Anyone have any experience with this, or ideas how I might prevent it?
I know this answer comes years later but if new readers run into problems with caching try setting:
Metadata Pooling = false, Self Tuning = False and Statement Cache Size = 0
...in the connection string. Keep in mind that there are performance implications for doing so.
https://docs.oracle.com/database/122/ODPNT/featConnecting.htm#GUID-0CFEB161-68EF-4BC2-8943-3BDFFB878602
Maybe post some of your C# code. The following is a test that behaves as expected, meaning I can see the new column immediately after adding it. This is using odp 11.2 rel 5 hitting an 11g db, using 4.0 framework:
The test table is:
CREATE TABLE T1
(
DTE DATE default sysdate
);
Drop and recreate it after each run of the following C# code (a bit dirty but anyway):
string connStr = "User Id=xxx;Password=yyy;Data Source=my11gDb;";
using (OracleConnection con = new OracleConnection(connStr))
{
string s = "ALTER TABLE T1 ADD (added_col VARCHAR2(10))";
using (OracleCommand cmd = new OracleCommand(s, con))
{
con.Open();
cmd.ExecuteNonQuery();
string s2 = "select column_name from all_tab_columns where table_name = 'T1'";
//con.FlushCache(); // doesn't seem to matter, works with or without
using (OracleCommand cmd2 = new OracleCommand(s2, con))
{
OracleDataReader rdr = cmd2.ExecuteReader();
for (int i = 0; rdr.Read(); i++)
{
Console.WriteLine("Column {0} => {1}",i+1,rdr.GetString(0));
}
rdr.Close();
}
}
}
Output:
Column 1 => DTE
Column 2 => ADDED_COL
Edit:
Ah, ok, I see what you're saying, it looks like statement caching. I played around with changing the cache size to 0 (in conn string, use "Statement Cache Size=0"), and also tried cmd.AddToStatementCache = false, but these did not work.
One thing that does work is to use a slightly different string, like adding a space. I know its a hack, but this is all I can get to work for me anyway.
Try your example with:
var sql3 = "SELECT * FROM People";
var sql5 = "SELECT * FROM People "; // note extra space
And use sql3 before adding column, and sql5 after adding a column.
Hope that helps

Add row into database, get id and populate second table

I'm not great at .NET but am learning (at least trying to! ;) ). However, this bit of code I'm working has me baffled. What I want to do is insert a row into a SQL Server 2008 database table called Comment, then use the id of this inserted row to populate a second table (CommentOtherAuthor) with new rows of data. Basically, a comment can have multiple authors.
Here's the code:
public static Comment MakeNew(int parentNodeId, string firstname, string surname, string occupation, string affiliation, string title, string email, bool publishemail, bool competinginterests, string competingintereststext, string[] otherfirstname, string[] othersurname, string[] otheroccupation, string[] otheraffiliation, string[] otheremail, bool approved, bool spam, DateTime created, string commentText, int statusId)
{
var c = new Comment
{
ParentNodeId = parentNodeId,
FirstName = firstname,
Surname = surname,
Occupation = occupation,
Affiliation = affiliation,
Title = title,
Email = email,
PublishEmail = publishemail,
CompetingInterests = competinginterests,
CompetingInterestsText = competingintereststext,
OtherFirstName = otherfirstname,
OtherSurname = othersurname,
OtherOccupation = otheroccupation,
OtherAffiliation = otheraffiliation,
OtherEmail = otheremail,
Approved = approved,
Spam = spam,
Created = created,
CommenText = commentText,
StatusId = statusId
};
var sqlHelper = DataLayerHelper.CreateSqlHelper(umbraco.GlobalSettings.DbDSN);
c.Id = sqlHelper.ExecuteScalar<int>(
#"insert into Comment(mainid,nodeid,firstname,surname,occupation,affiliation,title,email,publishemail,competinginterests,competingintereststext,comment,approved,spam,created,statusid)
values(#mainid,#nodeid,#firstname,#surname,#occupation,#affiliation,#title,#email,#publishemail,#competinginterests,#competingintereststext,#comment,#approved,#spam,#created,#statusid)",
sqlHelper.CreateParameter("#mainid", -1),
sqlHelper.CreateParameter("#nodeid", c.ParentNodeId),
sqlHelper.CreateParameter("#firstname", c.FirstName),
sqlHelper.CreateParameter("#surname", c.Surname),
sqlHelper.CreateParameter("#occupation", c.Occupation),
sqlHelper.CreateParameter("#affiliation", c.Affiliation),
sqlHelper.CreateParameter("#title", c.Title),
sqlHelper.CreateParameter("#email", c.Email),
sqlHelper.CreateParameter("#publishemail", c.PublishEmail),
sqlHelper.CreateParameter("#competinginterests", c.CompetingInterests),
sqlHelper.CreateParameter("#competingintereststext", c.CompetingInterestsText),
sqlHelper.CreateParameter("#comment", c.CommenText),
sqlHelper.CreateParameter("#approved", c.Approved),
sqlHelper.CreateParameter("#spam", c.Spam),
sqlHelper.CreateParameter("#created", c.Created),
sqlHelper.CreateParameter("#statusid", c.StatusId));
c.OnCommentCreated(EventArgs.Empty);
for (int x = 0; x < otherfirstname.Length; x++)
{
sqlHelper.ExecuteScalar<int>(
#"insert into CommentOtherAuthor(firstname,surname,occupation,affiliation,email,commentid) values(#firstname,#surname,#occupation,#affiliation,#email,#commentid)",
sqlHelper.CreateParameter("#firstname", otherfirstname[x]),
sqlHelper.CreateParameter("#surname", othersurname[x]),
sqlHelper.CreateParameter("#occupation", otheroccupation[x]),
sqlHelper.CreateParameter("#affiliation", otheraffiliation[x]),
sqlHelper.CreateParameter("#email", otheremail[x]),
sqlHelper.CreateParameter("#commentid", 123)
);
}
if (c.Spam)
{
c.OnCommentSpam(EventArgs.Empty);
}
if (c.Approved)
{
c.OnCommentApproved(EventArgs.Empty);
}
return c;
}
The key line is:
sqlHelper.CreateParameter("#commentid", 123)
At the moment, I'm just hard-coding the id for the comment as 123, but really I need it to be the id of the record just inserted into the comment table.
I just don't really understand how to grab the last insert from the table Comment without doing a new
SELECT TOP 1 id FROM Comment ORDER BY id DESC
which doesn't strike me as the best way to do this.
Can anyone suggest how to get this working?
Many thanks!
That SELECT TOP 1 id ... query most likely wouldn't give you the proper results anyway in a system under load. If you have 20 or 50 clients inserting comments at the same time, by the time you query the table again, chances are very high you would be getting someone else's id ...
The best way I see to do this would be:
add an OUTPUT clause to your original insert and capture the newly inserted ID
use that ID for your second insert
Something along the lines of:
c.Id = sqlHelper.ExecuteScalar<int>(
#"insert into Comment(......)
output Inserted.ID
values(.............)",
Using this approach, your c.Id value should now be the newly inserted ID - use that in your next insert statement! (note: right now, you're probably always getting a 1 back - the number of rows affected by your statement ...)
This approach assumes your table Comment has a column of type INT IDENTITY that will be automatically set when you insert a new row into it.
for (int x = 0; x < otherfirstname.Length; x++)
{
sqlHelper.ExecuteScalar<int>(
#"insert into CommentOtherAuthor(.....) values(.....)",
sqlHelper.CreateParameter("#firstname", otherfirstname[x]),
sqlHelper.CreateParameter("#surname", othersurname[x]),
sqlHelper.CreateParameter("#occupation", otheroccupation[x]),
sqlHelper.CreateParameter("#affiliation", otheraffiliation[x]),
sqlHelper.CreateParameter("#email", otheremail[x]),
sqlHelper.CreateParameter("#commentid", c.Id) <<=== use that value you got back!
);
}
Assuming you are using Microsoft SQL Server, you could design your table Comment so the column Id has the property Identity set to true. This way the database will generate and auto-increment the id each time a row is inserted into the table.
You would have to use the following line in your SQL request:
OUTPUT INSERTED.Id
in order to return this Id to your C# code when the request is executed.

Categories