How to prevent duplicates in database - c#

I have been trying to prevent duplicates and get an error message to show up if a duplicated Email or Username (or both) has been typed, I wonder what's wrong with my code.
I have tried some of the solutions for similar problems, but they didn't seem to work. I am not sure if there is something wrong with my code or another way of doing it. It just runs and executes the code and the results gets added to the database, even if they are duplicated.
sqlCon.Open();
string query = "SELECT COUNT(*) FROM SSUser WHERE username=#username AND password=#password AND email=#email";
SqlCommand c1 = new SqlCommand(query);
SqlCommand c = new SqlCommand("insert into SSUser values(#username, #password, #email)", sqlCon);
c.Parameters.AddWithValue("#username", register_username.Text);
c.Parameters.AddWithValue("#password", register_password.Text);
c.Parameters.AddWithValue("#email", register_mail.Text);
SqlCommand check_username = new SqlCommand("SELECT COUNT(*) FROM SSUser WHERE (username=#username) AND (email = #email)", sqlCon);
check_username.Parameters.AddWithValue("#username", register_username.Text);
check_username.Parameters.AddWithValue("#email", register_mail.Text);
int check = (int)check_username.ExecuteScalar();
if (check > 0)
{
register_error.Visible = true;
}
else
{
if (register_c.Text != register_password.Text)
{
register_error.Visible = true;
}
else
{
c.ExecuteNonQuery();
register_username.Text = "";
register_password.Text = "";
register_c.Text = "";
register_mail.Text = "";
Response.Redirect("Login.aspx");
}
}

Adding to Gordon Linoff's answer:
After you added the unique constraint to the appropriate attributes in your database you should be able to catch a SqlException:
try {
c.ExecuteNonQuery();
}
catch (SqlException ex)
{
}

To prevent duplicates, create unique constraints or indexes in the database:
alter table ssuser add constraint unq_ssuser_username unique (username);
alter table ssuser add constraint unq_ssuer_email unique (email);
Any insert or update that would create a duplicate will return an error. You may want to catch the error when you attempt inserts and updates.

Please consider using your database layer for this; here is a working example of T-SQL that does exactly that:
create table [dbo].[SSUser] (
[UserId] bigint not null identity (0, 1)
, [UserName] nvarchar(255) not null
, [Email] nvarchar(255) not null
, [PasswordHash] varbinary(64) null
, constraint [dbo_SSUser_Pk] primary key clustered ([UserName] asc) with (data_compression = page)
);
go
create type [dbo].[ISSUser] as table (
[UserName] nvarchar(255) not null
, [Email] nvarchar(255) not null
, [PasswordHash] varbinary(64) null
, primary key clustered ([UserName] asc)
);
go
create procedure [dbo].[usp_SSUser_Insert] (
#users [dbo].[ISSUser] readonly
)
as
begin;
set nocount on;
set xact_abort on;
insert into [dbo].[SSUser] (
[UserName]
, [Email]
, [PasswordHash]
)
output [inserted].[UserId]
, [inserted].[Email]
, [inserted].[PasswordHash]
select a.[UserName]
, a.[Email]
, a.[PasswordHash]
from #users as a;
end;
And the accompanying C# code that'll call the procedure and trap any errors:
var connectionString = "Data Source=.;Initial Catalog=Koholint;Trusted_Connection=True;";
var userName = register_username.Text;
var email = register_mail.Text;
var passwordHash = register_password.HashBytes;
try {
var tableMetadata = new[] {
new SqlMetaData("UserName", SqlDbType.NVarChar, 255),
new SqlMetaData("Email", SqlDbType.NVarChar, 255),
new SqlMetaData("PasswordHash", SqlDbType.VarBinary, 64),
};
var tableValues = new SqlDataRecord(tableMetadata);
tableValues.SetValue(0, userName);
tableValues.SetValue(1, email);
tableValues.SetValue(2, passwordHash);
using (var connection = new SqlConnection(connectionString))
using (var command = connection.CreateCommand()) {
command.CommandText = "[dbo].[usp_SSUser_Insert]";
command.CommandTimeout = 15;
command.CommandType = CommandType.StoredProcedure;
var tableParameter = new SqlParameter("users", SqlDbType.Structured);
tableParameter.TypeName = "[dbo].[ISSUser]";
tableParameter.Value = new[] { tableValues };
command.Parameters.Add(tableParameter);
connection.Open();
using (var reader = command.ExecuteReader()) {
do {
while (reader.Read()) {
Console.WriteLine(reader.GetInt64(0)); // TODO: something more useful, or maybe nothing...
}
} while (reader.NextResult());
}
}
}
catch (SqlException e) {
register_error.Visible = true;
if (e.Number == 2627) {
// special handling for primary key/unique constraint violation
}
else {
throw; // rethrow everything else
}
}
register_username.Text = "";
register_password.Text = "";
register_mail.Text = "";
Response.Redirect("Login.aspx");
Why bother with all of this?
Number one, it truly prevents duplicates. It makes absolutely no sense to check for duplicates in client code if you want to prevent them in the database; simply prevent them from ever happening using a primary key or unique constraint.
Another major benefit is that we save at least one trip to the database. The OP's original code has to query the database in order to check for duplicates; not only does this fail in the face of concurrent writers who use the same key value but it is also quite expensive in terms of time.
The table-valued parameter is used in order to encapsulate all inputs into a single "interface" that makes it easier to specify the contract between C# and T-SQL. It also has the side benefit of allowing us to insert many different users in a single transaction instead of making calls in some sort of loop.

Related

How to fix FK Constraint insert Exception

According to my question with weird problem specified here how to fix
System.Data.SqlClient.SqlException: String or binary data would be truncated in table
My problem is, that if I am saving new problem into the database, its ID is always set to 0 (I checked this out in debugging), which then throws
System.Data.SqlClient.SqlException: The INSERT statement conflicted with the FOREIGN KEY constraint "FK__Alert__Problem_I__17F790F9". The conflict occurred in database "SmartOne", table "dbo.Problem", column 'id'
But in SQL Server Management Studio, the ID is set correctly (ID is defined as an Identity column).
Where both I am using is in my question mentioned below. Thanks for any ideas or advice.
Method that saves Problem:
public void Save(Problem element)
{
using (SqlConnection conn = new SqlConnection(DatabaseSingleton.connString))
{
conn.Open();
using (SqlCommand command = new SqlCommand("INSERT INTO Problem VALUES " +
"(#nameOfAlert, #value, #result, #message_ID) ", conn))
{
command.Parameters.Add(new SqlParameter("#nameOfAlert", element.NameOfAlert));
command.Parameters.Add(new SqlParameter("#value", (int)element.Value));
command.Parameters.Add(new SqlParameter("#result", (int)element.Result));
command.Parameters.Add(new SqlParameter("#message_ID", element.Message_Id));
command.ExecuteNonQuery();
command.CommandText = "Select ##Identity";
}
conn.Close();
}
}
Method that saves an Alert:
public void Save(Alert element)
{
using (SqlConnection conn = new SqlConnection(DatabaseSingleton.connString))
{
conn.Open();
using (SqlCommand command = new SqlCommand("INSERT INTO [Alert] VALUES (#message_ID, #date, #email, #AMUser_ID, #Problem_ID) ", conn))
{
command.Parameters.Add(new SqlParameter("#message_ID", element.Id_MimeMessage));
command.Parameters.Add(new SqlParameter("#date", element.Date));
command.Parameters.Add(new SqlParameter("#email", element.Email));
command.Parameters.Add(new SqlParameter("#AMUser_ID", element.User_ID));
command.Parameters.Add(new SqlParameter("#Problem_ID", element.Problem_ID));
command.ExecuteNonQuery();
command.CommandText = "Select ##Identity";
}
conn.Close();
}
}
SQL Scheme
CREATE TABLE [dbo].[Alert](
[id] [int] IDENTITY(1,1) NOT NULL,
[message_ID] [varchar](100) NOT NULL,
[date] [datetime] NOT NULL,
[email] [varchar](50) NOT NULL,
[AMUser_ID] [int] NOT NULL,
[Problem_ID] [int] NOT NULL);
//Where is ID, it means FK ID
CREATE TABLE [dbo].[Problem](
[id] [int] IDENTITY(1,1) NOT NULL,
[nameOfAlert] [varchar](50) NOT NULL,
[Value_ID] [int] NOT NULL,
[Result_ID] [int] NOT NULL,
[message_ID] [varchar](100) NOT NULL);
One problem might be that you're never actually getting back the inserted IDENTITY value from your first insert - thus you aren't using any valid ProblemId value for your second insert.
Try something like this:
public void Save(Problem element)
{
using (SqlConnection conn = new SqlConnection(DatabaseSingleton.connString))
{
conn.Open();
// define INSERT query - I'd *strongly* recommend specifying all
// columns you're inserting into!
// Also: run the "SELECT SCOPE_IDENTITY()" right after the INSERT
string insertQry = "INSERT INTO dbo.Problem(NameOfAlert, Value, Result, MessageId) " +
"VALUES (#nameOfAlert, #value, #result, #message_ID); " +
"SELECT SCOPE_IDENTITY();";
using (SqlCommand command = new SqlCommand(insertQry, conn))
{
// also here: define the *datatype* of the parameter, and use
// .Value = to set the value.
// Since you haven't shown what the table looks like, I'm just
// **guessing** the datatype and max length for the string parameters - adapt as needed!
command.Parameters.Add("#nameOfAlert", SqlDbType.VarChar, 100).Value = element.NameOfAlert;
command.Parameters.Add("#value", SqlDbType.Int).Value = (int)element.Value;
command.Parameters.Add("#result", SqlDbType.Int).Value = (int)element.Result;
command.Parameters.Add("#message_ID", SqlDbType.VarChar, 100).Value = element.Message_Id;
// since your statement now returns the ID value - use "ExecuteScalar"
var returnedValue = command.ExecuteScalar();
if (returnedValue != null)
{
// if a value was returned - convert to INT
int problemId = Convert.ToInt32(returnedValue);
}
}
conn.Close();
}
}
Now, in case the INSERT works, you get back the ProblemId value from the identity column, and you can now use this in your second insert as value for the #ProblemId parameter.
For saving the id into other table, you have to complete the insertion first. if the insertion is not completed then you can not get the problem id (if it is the primary key, which is supposed to be returned by saving the datas). Only after saving the data to the table, you are going to have the problem id then you can use it as FK in the same method.
if i say, there is two table and you are going to use the first table primary key in the second table as FK. Then you need to complete the first table row insertion. after excuting the query for the first table, you will get the primary key of that row and you can use easily in the second table as FK.

Why is this SQLite Script Affecting Multiple Rows?

I have the following simple SQLite script to create a new database with a versioning table:
BEGIN TRANSACTION;
CREATE TABLE IF NOT EXISTS `db_versions` (
`version` integer NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
`name` varchar ( 50 ) DEFAULT NULL UNIQUE,
`date_defined` datetime DEFAULT NULL,
`comments` text
);
INSERT INTO `db_versions` VALUES (0,'initial-create','2017-12-02 14:41:56',NULL);
COMMIT;
Running this script in the DB Browser for SQLite logs correctly logs that only 1 row is affected (inserted). However, when I try to execute this script in code with Mono (Mono.Data.Sqlite), the script apparently affects 2 rows. Here is that code:
using (var conn = new SqliteConnection(_connStr)) {
await conn.OpenAsync(cancellationToken);
using (SqliteCommand comm = conn.CreateCommand()) {
comm.CommandType = CommandType.Text;
comm.CommandText = #"
BEGIN TRANSACTION;
CREATE TABLE IF NOT EXISTS `db_versions` (
`version` integer NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
`name` varchar ( 50 ) DEFAULT NULL UNIQUE,
`date_defined` datetime DEFAULT NULL,
`comments` text
);
INSERT INTO `db_versions` VALUES (0,'initial-create','2017-12-02 14:41:56',NULL);
COMMIT;
";
int rowsAffected = await comm.ExecuteNonQueryAsync(cancellationToken);
if (rowsAffected > 1) {
// Why is this code running??
}
}
}
Does anyone know why I'm getting these different results?
Gah, I figured it out. The integer version field was being defined AUTOINCREMENT, which also adds the largest ROWID to an internal sqlite_sequence table. So there was a 2nd row being added.

Insert statement conflict with foriegn key fk_student, conflict database "id" column in student

protected void searchupdate_Click(object sender, EventArgs e)
{
SqlConnection con = Connection.DBconnection();
{
SqlCommand com = new SqlCommand("sp_searchupdate", con);
com.CommandType = CommandType.StoredProcedure;
com.Parameters.AddWithValue("#id", txtid.Text.Trim());
com.Parameters.AddWithValue("#id_student", textstudentid.Text.Trim());
com.Parameters.AddWithValue("#tamil", txttamil.Text.Trim());
com.Parameters.AddWithValue("#english", txtenglish.Text.Trim());
com.Parameters.AddWithValue("#maths", txtmaths.Text.Trim());
com.Parameters.AddWithValue("#science", txtscience.Text.Trim());
com.Parameters.AddWithValue("#socialScience", txtsocialscience.Text.Trim());
SqlParameter retval = new SqlParameter("#output", SqlDbType.VarChar, 50);
retval.Direction = ParameterDirection.Output;
com.Parameters.Add(retval);
com.ExecuteNonQuery();
string Output = retval.Value.ToString();
output.Text = Output;
textstudentid.Text = string.Empty;
txttamil.Text = string.Empty;
txtenglish.Text = string.Empty;
txtmaths.Text = string.Empty;
txtscience.Text = string.Empty;
txtsocialscience.Text = string.Empty;
}
stored procedure:
ALTER PROCEDURE sp_searchupdate
(
#id int,
#id_student int,
#output varchar(50) output,
#Tamil Varchar (100),
#English varchar (50),
#Maths Varchar (50),
#Science Varchar (50),
#SocialScience Varchar (50)
)
AS
IF EXISTS (SELECT * FROM studentresult WHERE id=#id)
BEGIN
UPDATE studentresult SET Tamil = #Tamil,English = #English, Maths = #Maths,Science = #Science,SocialScience = #SocialScience WHERE id = #id
SET #output='Updated'
END
ELSE
BEGIN
INSERT INTO studentresult (id_student,Tamil,English,Maths,Science,SocialScience) values (#id_student,#Tamil,#English,#Maths,#Science,#SocialScience)
SET #output='Inserted'
END
when i enter input value and click update.. it shows the following error:
Insert statement conflict with foreign key fk_student.
The statement terminated
I'm new to .net, can anyone help me what my mistake.. or what should i do?
Any help would be highly appreciated..
Thanks,
Most probably, you are trying to insert an ID that is not present in the primary key of the referencing table.
This kind of issue happens when bad data is passed into tables and two tables have foreign key constraint defined between them which wont allow such data to be inserted.
The rule is like this, a FK (Foreign key) cannot have a value in that column that is not also in the primary key column of the referenced table. So you might have to check on the values that you are passing through your queries.
Hope this helps.

SQLCE: Why I get "duplicate value" error? The field is identity enabled?

In my query I don't use primary key field because identity setting is enabled.
string sql = #"
INSERT INTO [tblTemplates] (personID, hash, data)
VALUES (#personID, #hash, #data)";
cmd = new SqlCeCommand(sql, cn);
cmd.Parameters.AddWithValue("#personID", newTemplate.personID);
cmd.Parameters.AddWithValue("#hash", newTemplate.templateHash);
cmd.Parameters.AddWithValue("#data", newTemplate.templateData);
cmd.ExecuteNonQuery();
Randomly I can or cannot insert a record then an exception thrown:
A duplicate value cannot be inserted into a unique index.
[ Table name = tblTemplates,Constraint name = PK_tblTemplates_templateID
]
This is the table schema:
-- Script Date: 26.08.2011 10:37 - Generated by ExportSqlCe version 3.5.1.5
CREATE TABLE [tblTemplates] (
[templateID] int NOT NULL IDENTITY (1,1)
, [hash] nvarchar(100) NOT NULL
, [data] image NOT NULL
, [personID] int NOT NULL
);
GO
ALTER TABLE [tblTemplates] ADD CONSTRAINT [PK__tblTemplates__templateID] PRIMARY KEY ([templateID]);
GO
CREATE INDEX [IDX_tblTemplates_personID] ON [tblTemplates] ([personID] ASC);
GO
CREATE UNIQUE INDEX [UQ__tblTemplates__templateID] ON [tblTemplates] ([templateID] ASC);
GO
Why I get this error?
It seems like a bug!
Workaround: Converting field data type from int to uniqueidentifier works.
My workaround attempts:
Attempt #1: Same connection
bool executed = false;
int counter = 0;
while (!executed)
{
try
{
cmd.ExecuteNonQuery();
succes = true;
}
catch (Exception ex)
{
Console.WriteLine("SERVER> (Error) Exception in AddTemplate() {0},{1}", ex.Source, ex.Message);
System.Threading.Thread.Sleep(100);
}
counter++;
}
Result: This seems like an endless loop.
Attempt #2: New connection
try
{
cmd.ExecuteNonQuery();
succes = true;
}
catch (Exception ex)
{
Console.WriteLine("SERVER> (Error) Exception in AddTemplate() {0},{1}", ex.Source, ex.Message);
System.Threading.Thread.Sleep(100);
AddTemplate(newTemplate); //Warning: Recursive call!
}
Result: This try helped after a few recursive calls.
I had similar problem. I used IDENTITY_INSERT on my table like
SET IDENTITY_INSERT MyTable ON;
-- some identity insert on MyTable
SET IDENTITY_INSERT MyTable OFF;
After this, all inserts on MyTable throw "duplicate value" error.
Solution to this problem was
var cmd = Connection.CreateCommand();
cmd.CommandText = "SELECT MAX([Id] ) + 1 from [MyTable]";
object i = cmd.ExecuteScalar();
if (i != null && i is int)
{
cmd.CommandText = "ALTER TABLE [MyTable] ALTER COLUMN [Id] IDENTITY (" + i + ",1)";
cmd.ExecuteNonQuery();
}

How to get last inserted id?

I have this code:
string insertSql =
"INSERT INTO aspnet_GameProfiles(UserId,GameId) VALUES(#UserId, #GameId)";
using (SqlConnection myConnection = new SqlConnection(myConnectionString))
{
myConnection.Open();
SqlCommand myCommand = new SqlCommand(insertSql, myConnection);
myCommand.Parameters.AddWithValue("#UserId", newUserId);
myCommand.Parameters.AddWithValue("#GameId", newGameId);
myCommand.ExecuteNonQuery();
myConnection.Close();
}
When I insert into this table, I have an auto_increment int primary key column called GamesProfileId, how can i get the last inserted one after this so I can use that id to insert into another table?
For SQL Server 2005+, if there is no insert trigger, then change the insert statement (all one line, split for clarity here) to this
INSERT INTO aspnet_GameProfiles(UserId,GameId)
OUTPUT INSERTED.ID
VALUES(#UserId, #GameId)
For SQL Server 2000, or if there is an insert trigger:
INSERT INTO aspnet_GameProfiles(UserId,GameId)
VALUES(#UserId, #GameId);
SELECT SCOPE_IDENTITY()
And then
Int32 newId = (Int32) myCommand.ExecuteScalar();
You can create a SqlCommand with CommandText equal to
INSERT INTO aspnet_GameProfiles(UserId, GameId) OUTPUT INSERTED.ID VALUES(#UserId, #GameId)
and execute int id = (int)command.ExecuteScalar.
This MSDN article will give you some additional techniques.
string insertSql =
"INSERT INTO aspnet_GameProfiles(UserId,GameId) VALUES(#UserId, #GameId)SELECT SCOPE_IDENTITY()";
int primaryKey;
using (SqlConnection myConnection = new SqlConnection(myConnectionString))
{
myConnection.Open();
SqlCommand myCommand = new SqlCommand(insertSql, myConnection);
myCommand.Parameters.AddWithValue("#UserId", newUserId);
myCommand.Parameters.AddWithValue("#GameId", newGameId);
primaryKey = Convert.ToInt32(myCommand.ExecuteScalar());
myConnection.Close();
}
This will work.
I had the same need and found this answer ..
This creates a record in the company table (comp), it the grabs the auto ID created on the company table and drops that into a Staff table (staff) so the 2 tables can be linked, MANY staff to ONE company. It works on my SQL 2008 DB, should work on SQL 2005 and above.
===========================
CREATE PROCEDURE [dbo].[InsertNewCompanyAndStaffDetails]
#comp_name varchar(55) = 'Big Company',
#comp_regno nchar(8) = '12345678',
#comp_email nvarchar(50) = 'no1#home.com',
#recID INT OUTPUT
-- The '#recID' is used to hold the Company auto generated ID number that we are about to grab
AS
Begin
SET NOCOUNT ON
DECLARE #tableVar TABLE (tempID INT)
-- The line above is used to create a tempory table to hold the auto generated ID number for later use. It has only one field 'tempID' and its type INT is the same as the '#recID'.
INSERT INTO comp(comp_name, comp_regno, comp_email)
OUTPUT inserted.comp_id INTO #tableVar
-- The 'OUTPUT inserted.' line above is used to grab data out of any field in the record it is creating right now. This data we want is the ID autonumber. So make sure it says the correct field name for your table, mine is 'comp_id'. This is then dropped into the tempory table we created earlier.
VALUES (#comp_name, #comp_regno, #comp_email)
SET #recID = (SELECT tempID FROM #tableVar)
-- The line above is used to search the tempory table we created earlier where the ID we need is saved. Since there is only one record in this tempory table, and only one field, it will only select the ID number you need and drop it into '#recID'. '#recID' now has the ID number you want and you can use it how you want like i have used it below.
INSERT INTO staff(Staff_comp_id)
VALUES (#recID)
End
-- So there you go. You can actually grab what ever you want in the 'OUTPUT inserted.WhatEverFieldNameYouWant' line and create what fields you want in your tempory table and access it to use how ever you want.
I was looking for something like this for ages, with this detailed break down, I hope this helps.
In pure SQL the main statement kools like:
INSERT INTO [simbs] ([En]) OUTPUT INSERTED.[ID] VALUES ('en')
Square brackets defines the table simbs and then the columns En and ID, round brackets defines the enumeration of columns to be initiated and then the values for the columns, in my case one column and one value. The apostrophes enclose a string
I will explain you my approach:
It might be not easy to understand but i hope useful to get the big picture around using the last inserted id. Of course there are alternative easier approaches. But I have reasons to keep mine. Associated functions are not included, just their names and parameter names.
I use this method for medical artificial intelligence
The method check if the wanted string exist in the central table (1). If the wanted string is not in the central table "simbs", or if duplicates are allowed, the wanted string is added to the central table "simbs" (2). The last inseerted id is used to create associated table (3).
public List<int[]> CreateSymbolByName(string SymbolName, bool AcceptDuplicates)
{
if (! AcceptDuplicates) // check if "AcceptDuplicates" flag is set
{
List<int[]> ExistentSymbols = GetSymbolsByName(SymbolName, 0, 10); // create a list of int arrays with existent records
if (ExistentSymbols.Count > 0) return ExistentSymbols; //(1) return existent records because creation of duplicates is not allowed
}
List<int[]> ResultedSymbols = new List<int[]>(); // prepare a empty list
int[] symbolPosition = { 0, 0, 0, 0 }; // prepare a neutral position for the new symbol
try // If SQL will fail, the code will continue with catch statement
{
//DEFAULT und NULL sind nicht als explizite Identitätswerte zulässig
string commandString = "INSERT INTO [simbs] ([En]) OUTPUT INSERTED.ID VALUES ('" + SymbolName + "') "; // Insert in table "simbs" on column "En" the value stored by variable "SymbolName"
SqlCommand mySqlCommand = new SqlCommand(commandString, SqlServerConnection); // initialize the query environment
SqlDataReader myReader = mySqlCommand.ExecuteReader(); // last inserted ID is recieved as any resultset on the first column of the first row
int LastInsertedId = 0; // this value will be changed if insertion suceede
while (myReader.Read()) // read from resultset
{
if (myReader.GetInt32(0) > -1)
{
int[] symbolID = new int[] { 0, 0, 0, 0 };
LastInsertedId = myReader.GetInt32(0); // (2) GET LAST INSERTED ID
symbolID[0] = LastInsertedId ; // Use of last inserted id
if (symbolID[0] != 0 || symbolID[1] != 0) // if last inserted id succeded
{
ResultedSymbols.Add(symbolID);
}
}
}
myReader.Close();
if (SqlTrace) SQLView.Log(mySqlCommand.CommandText); // Log the text of the command
if (LastInsertedId > 0) // if insertion of the new row in the table was successful
{
string commandString2 = "UPDATE [simbs] SET [IR] = [ID] WHERE [ID] = " + LastInsertedId + " ;"; // update the table by giving to another row the value of the last inserted id
SqlCommand mySqlCommand2 = new SqlCommand(commandString2, SqlServerConnection);
mySqlCommand2.ExecuteNonQuery();
symbolPosition[0] = LastInsertedId; // mark the position of the new inserted symbol
ResultedSymbols.Add(symbolPosition); // add the new record to the results collection
}
}
catch (SqlException retrieveSymbolIndexException) // this is executed only if there were errors in the try block
{
Console.WriteLine("Error: {0}", retrieveSymbolIndexException.ToString()); // user is informed about the error
}
CreateSymbolTable(LastInsertedId); //(3) // Create new table based on the last inserted id
if (MyResultsTrace) SQLView.LogResult(LastInsertedId); // log the action
return ResultedSymbols; // return the list containing this new record
}
I tried the above but they didn't work, i found this thought, that works a just fine for me.
var ContactID = db.GetLastInsertId();
Its less code and i easy to put in.
Hope this helps someone.
You can also use a call to SCOPE_IDENTITY in SQL Server.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
namespace DBDemo2
{
public partial class Form1 : Form
{
string connectionString = "Database=company;Uid=sa;Pwd=mypassword";
System.Data.SqlClient.SqlConnection connection;
System.Data.SqlClient.SqlCommand command;
SqlParameter idparam = new SqlParameter("#eid", SqlDbType.Int, 0);
SqlParameter nameparam = new SqlParameter("#name", SqlDbType.NChar, 20);
SqlParameter addrparam = new SqlParameter("#addr", SqlDbType.NChar, 10);
public Form1()
{
InitializeComponent();
connection = new System.Data.SqlClient.SqlConnection(connectionString);
connection.Open();
command = new System.Data.SqlClient.SqlCommand(null, connection);
command.CommandText = "insert into employee(ename, city) values(#name, #addr);select SCOPE_IDENTITY();";
command.Parameters.Add(nameparam);
command.Parameters.Add(addrparam);
command.Prepare();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void buttonSave_Click(object sender, EventArgs e)
{
try
{
int id = Int32.Parse(textBoxID.Text);
String name = textBoxName.Text;
String address = textBoxAddress.Text;
command.Parameters[0].Value = name;
command.Parameters[1].Value = address;
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
reader.Read();
int nid = Convert.ToInt32(reader[0]);
MessageBox.Show("ID : " + nid);
}
/*int af = command.ExecuteNonQuery();
MessageBox.Show(command.Parameters["ID"].Value.ToString());
*/
}
catch (NullReferenceException ne)
{
MessageBox.Show("Error is : " + ne.StackTrace);
}
catch (Exception ee)
{
MessageBox.Show("Error is : " + ee.StackTrace);
}
}
private void buttonSave_Leave(object sender, EventArgs e)
{
}
private void Form1_Leave(object sender, EventArgs e)
{
connection.Close();
}
}
}
There are all sorts of ways to get the Last Inserted ID but the easiest way I have found is by simply retrieving it from the TableAdapter in the DataSet like so:
<Your DataTable Class> tblData = new <Your DataTable Class>();
<Your Table Adapter Class> tblAdpt = new <Your Table Adapter Class>();
/*** Initialize and update Table Data Here ***/
/*** Make sure to call the EndEdit() method ***/
/*** of any Binding Sources before update ***/
<YourBindingSource>.EndEdit();
//Update the Dataset
tblAdpt.Update(tblData);
//Get the New ID from the Table Adapter
long newID = tblAdpt.Adapter.InsertCommand.LastInsertedId;
Hope this Helps ...
After inserting any row you can get last inserted id by below line of query.
INSERT INTO aspnet_GameProfiles(UserId,GameId)
VALUES(#UserId, #GameId);
SELECT ##IDENTITY
If you're using executeScalar:
cmd.ExecuteScalar();
result_id=cmd.LastInsertedId.ToString();
Maybe this answer helps as well as my database seems to have no column specified as "IDENTITY" (which is needed for "SELECT SCOPE_IDENTITY()" or "##IDENTITY" calls). Also my "ID" column was of type "binary(16)" so I needed to convert the output like stated below:
string returnId = BitConverter.ToString((byte[])cmd.ExecuteScalar()).Replace("-", "");
// skip the replace if you handle the hyphen otherwise
Use SELECT SCOPE_IDENTITY() in query
After this:
INSERT INTO aspnet_GameProfiles(UserId, GameId) OUTPUT INSERTED.ID VALUES(#UserId, #GameId)
Execute this
int id = (int)command.ExecuteScalar;
It will work
INSERT INTO aspnet_GameProfiles(UserId,GameId) VALUES(#UserId, #GameId)";
then you can just access to the last id by ordering the table in desc way.
SELECT TOP 1 UserId FROM aspnet_GameProfiles ORDER BY UserId DESC.
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
CREATE PROC [dbo].[spCountNewLastIDAnyTableRows]
(
#PassedTableName as NVarchar(255),
#PassedColumnName as NVarchar(225)
)
AS
BEGIN
DECLARE #ActualTableName AS NVarchar(255)
DECLARE #ActualColumnName as NVarchar(225)
SELECT #ActualTableName = QUOTENAME( TABLE_NAME )
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #PassedTableName
SELECT #ActualColumnName = QUOTENAME( COLUMN_NAME )
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME = #PassedColumnName
DECLARE #sql AS NVARCHAR(MAX)
SELECT #sql = 'select MAX('+ #ActualColumnName + ') + 1 as LASTID' + ' FROM ' + #ActualTableName
EXEC(#SQL)
END

Categories