how to generate unique max id from Data Base - c#

I create a Applicant Registration form where Applicant Registration ID is generated by "Select Max(ID)...." Query. when this query is fetch out the MaxID from Data Base then i increment this ID by Plus one(+1) in this way i generate a Registration ID for all Applicant who register himself. But there is one problem occurred when i run my project from server and multiple clients (Approximately 10) Applicant try to Register then there is "primary key violation exception" occurred. There is 5 Insert Query is executed one-by-one after Max Query is executed
Code is Given Below
public long getUid()
{
try
{
string qry = "select isnull(max(Temp_Applicant_RegNo),0) as appregno FROM Temp_Reg";
if (cs.State == ConnectionState.Closed)
{
cs.Open();
}
cmd = new SqlCommand(qry, cs);
dr = cmd.ExecuteReader();
long cid = 0;
if (dr.Read())
{
cid = long.Parse(dr["appregno"].ToString());
cid++;
}
if (cs.State == ConnectionState.Open)
{
cs.Close();
}
return cid;
}
catch (Exception ex)
{
lbl_ErrorMsg.Text = ex.Message;
return 0;
}
}
protected void Save_btn_Click(object sender, EventArgs e)
{
SqlTransaction trn = null;
try
{
long Regid = getUid();
con.Open();
trn = con.BeginTransaction();
cmd = new SqlCommand("insert into....", con, trn);
cmd.Parameters.AddWithValue("#RegNo", Regid);
cmd.ExecuteNonQuery();
cmd = new SqlCommand("insert into....", con, trn);
cmd.Parameters.AddWithValue("#RegNo", Regid);
cmd.ExecuteNonQuery();
cmd = new SqlCommand("insert into....", con, trn);
cmd.Parameters.AddWithValue("#RegNo", Regid);
cmd.ExecuteNonQuery();
trn.Commit();
}
catch (Exception ex)
{
lbl_ErrorMsg.Text = ex.Message;
trn.Rollback();
}
}
Please give me suggestion that how can i generate Max ID for Applicant so that there is no chance to any duplication. Because i am working in live project.
for there i am using Asp.net C#

Don't do that, let the database generate the key for you when you insert a new row. Here is for example how to do it with SQL Server or MySQL. If you really want to do it on the client, use GUIDs as keys because you can generate them without consulting the database. There are some minor issues with GUIDs as keys because they are usually partially random and this may have negative performance effects on clustered indices, but for 99.9 % of all databases they are just fine.

Solution 1:
You can create a table with only one column, For example "GeneralID", and in your application control this Id to insert in another tables.
Solution 2:
Another solution is create a table and only one column, and a trigger to each table before insert to popule the id getting frmo the "Ids table" to insert.

Before we had auto incrementing columns we would have a table to hold the IDs. It would only have 2 columns IdType varchar(10) and NextId int. Then in a stored proc we would have something like:
while(1=1)
begin
select #nextId = nextId
from MyIds
where IdType=#IdType
update MyIds
set nextId = #nextId + 1
where IdType=#IdType
and nextId = #nextId
if(##ROWCOUNT > 0)
break;
end
select #nextId as nextId
Note that this would only update in the second statement if the nextId didn't change. If it did change it would try again.

I don't see when do you save the new value into Temp_Reg, but how if you save that value immediately after calculation, then you can safety update others tables:
public long getUid()
{
try
{
string qry = "select isnull(max(Temp_Applicant_RegNo),0) as appregno FROM Temp_Reg";
if (cs.State == ConnectionState.Closed)
{
cs.Open();
}
cmd = new SqlCommand(qry, cs);
dr = cmd.ExecuteReader();
long cid = 0;
if (dr.Read())
{
cid = long.Parse(dr["appregno"].ToString());
cid++;
}
UPDATE Temp_reg HERE !!!!
if (cs.State == ConnectionState.Open)
{
cs.Close();
}
return cid;
}
catch (Exception ex)
{
lbl_ErrorMsg.Text = ex.Message;
return 0;
}
}
Then you'll have to take this update into account inside the catch block of Save_btn_Click.
All of this if you can't use Autonumbers but If you can, use it.

If you could change your field Temp_Applicant_RegNo in an IDENTITY column, then you don't need to worry about the next number assigned to your table Temp_Reg. It is all a jopb made by your database.
All you need to know is what number has been assigned and use that number in your subsequent inserts.
This could be easily done using the SELECT SCOPE_IDENTITY() after the insert in your
protected void Save_btn_Click(object sender, EventArgs e)
{
SqlTransaction trn = null;
try
{
con.Open();
trn = con.BeginTransaction();
cmd = new SqlCommand("insert into....; SELECT SCOPE_IDENTITY()", con, trn);
int Regid = Convert.ToInt32(cmd.ExecuteScalar());
cmd = new SqlCommand("insert into....", con, trn);
cmd.Parameters.AddWithValue("#RegNo", Regid);
cmd.ExecuteNonQuery();
cmd = new SqlCommand("insert into....", con, trn);
cmd.Parameters.AddWithValue("#RegNo", Regid);
cmd.ExecuteNonQuery();
trn.Commit();
}
catch (Exception ex)
{
lbl_ErrorMsg.Text = ex.Message;
trn.Rollback();
}
The trick is possible adding the SELECT SCOPE_IDENTITY() as a second query to the first insert and then call ExecuteScalar. ExecuteScalar executes the queries and then returns the value of the first column in the first row of the last query executed.

Related

C# Using ExecuteScalar() Method With Where Clause in SqlCommand

try
{
SqlCommand sqlCommand = new SqlCommand("SELECT COUNT(*) FROM Doctor WHERE Id = #id", sqlServerConnection);
sqlCommand.Parameters.AddWithValue("#id", id.Text);
int numberOfDoctors = (int) sqlCommand.ExecuteScalar();
if(numberOfDoctors == 1)
{
Console.WriteLine("Doctor is already in database.");
}
else
{
Console.WriteLine("There is no doctor with this Id.");
}
}
catch (Exception exc)
{
Console.WriteLine(exc);
}
I have a code like this. I have an application that has a connection with SQL database. Firstly, sqlServerConnection object is defined in the code correctly. There is no problem with that object. I have a Doctor table in the database. id. Text comes from Text element that is the value user typed in.
I want to be sure about whether this typed id is already in my database or not. Whichever value
I type in I always see "Doctor is already in database." message in the console. When I remove
WHERE clause from sqlCommand code works correctly. But when I add WHERE clause I can't track
whether this user with the given id is in my database or not. Could you please help me? Thank you
for your responses in advance. Have a great day :)
There are a number of issues with your code:
You should specify the type and length of the parameter explicitly
You need to dispose the connection and command objects
There is no need to use SELECT COUNT if there is only one row, you can just do SELECT 1
const string query = #"
SELECT 1
FROM Doctor
WHERE Id = #id;
";
try
{
using (var connection = new SqlConnection(yourConnString))
using (var sqlCommand = new SqlCommand(, sqlServerConnection);
{
sqlCommand.Parameters.Add("#id", SqlDbType.Char, 7).Value = id.Text;
connection.Open();
int numberOfDoctors = (sqlCommand.ExecuteScalar() as int) ?? 0; // will be null if no rows
connection.Close();
if(numberOfDoctors == 1)
{
Console.WriteLine("Doctor is already in database.");
}
else
{
Console.WriteLine("There is no doctor with this Id.");
}
}
}
catch (Exception exc)
{
Console.WriteLine(exc);
}
If there is no unique key on that column, you can instead do EXISTS:
SELECT CASE WHEN EXISTS (SELECT 1
FROM Doctor
WHERE Id = #id)
THEN 1 ELSE 0 END;
In practice you don't need to COUNT the whole table only to discover if your record exists or not.
try
{
string cmdText = #"IF EXISTS(SELECT 1 FROM Doctor WHERE Id = #id)
SELECT 1 ELSE SELECT 0";
SqlCommand sqlCommand = new SqlCommand(cmdText, sqlServerConnection);
sqlCommand.Parameters.Add("#id", SqlDbType.Char, 7).Value = id.Text;
int docExist = (int)sqlCommand.ExecuteScalar();
if(docExist == 1)
{
Console.WriteLine("Doctor is already in database.");
}
else
{
Console.WriteLine("There is no doctor with this Id.");
}
}
catch (Exception exc)
{
Console.WriteLine(exc);
}
The IF EXIST will stop to search if the a record exists while COUNT will do what is supposed to do, count the record that satisfy the condition till the end of the table.

Efficient Way to Update a lot of Rows from C#

I have a program where I open a SqlConnection, load up a list of objects, modify a value on each object, then update the rows in the SQL Server database. Because the modification requires string parsing I wasn't able to do with with purely T-SQL.
Right now I am looping through the list of objects, and running a SQL update in each iteration. This seems inefficient and I'm wondering if there is a more efficient way to do it using LINQ
The list is called UsageRecords. The value I'm updating is MthlyConsumption.
Here is my code:
foreach (var item in UsageRecords)
{
string UpdateQuery = #"UPDATE tbl810CTImport
SET MthlyConsumption = " + item.MthlyConsumption +
"WHERE ID = " + item.Id;
SqlCommand update = new SqlCommand(UpdateQuery, sourceConnection);
update.ExecuteNonQuery();
}
Try this instead:
string UpdateQuery = #"UPDATE tbl810CTImport SET MthlyConsumption = #consumption WHERE ID = #itemId";
var update = new SqlCommand(UpdateQuery, sourceConnection);
update.Parameters.Add("#consumption", SqlDbType.Int); // Specify the correct types here
update.Parameters.Add("#itemId", SqlDbType.Int); // Specify the correct types here
foreach (var item in UsageRecords)
{
update.Parameters[0].Value = item.MthlyConsumption;
update.Parameters[1].Value = item.Id;
update.ExecuteNonQuery();
}
It should be faster because:
You don't have to create the command each time.
You don't create a new string each time (concatenation)
The query is not parsed at every iteration (Just changes the parameters values).
And it will cache the execution plan. (Thanks to #JohnCarpenter from the comment)
You can either use
SqlDataAdapter - See How to perform batch update in Sql through C# code
or what I have previously done was one of the following:
Tear down the ID's in question, and re-bulkinsert
or
Bulk Insert the ID + new value into a staging table, and update the table on SQL server:
update u
set u.MthlyConsumption = s.MthlyConsumption
from tbl810CTImport u
inner join staging s on
u.id = s.id
In a situation like this, where you can't write a single update statement to cover all your bases, it's a good idea to batch up your statements and run more than one at a time.
var commandSB = new StringBuilder();
int batchCount = 0;
using (var updateCommand = sourceConnection.CreateCommand())
{
foreach (var item in UsageRecords)
{
commandSB.AppendFormat(#"
UPDATE tbl810CTImport
SET MthlyConsumption = #MthlyConsumption{0}
WHERE ID = #ID{0}",
batchCount
);
updateCommand.Parameters.AddWithValue(
"#MthlyConsumption" + batchCount,
item.MthlyConsumption
);
updateCommand.Parameters.AddWithValue(
"#ID" + batchCount,
item.MthlyConsumption
);
if (batchCount == 500) {
updateCommand.CommandText = commandSB.ToString();
updateCommand.ExecuteNonQuery();
commandSB.Clear();
updateCommand.Parameters.Clear();
batchCount = 0;
}
else {
batchCount++;
}
}
if (batchCount != 0) {
updateCommand.ExecuteNonQuery();
}
}
It should be as simple as this . . .
private void button1_Click(object sender, EventArgs e)
{
SqlConnection con = new SqlConnection("Server=YourServerName;Database=YourDataBaseName;Trusted_Connection=True");
try
{
//cmd new SqlCommand( "UPDATE Stocks
//SET Name = #Name, City = #cit Where FirstName = #fn and LastName = #add";
cmd = new SqlCommand("Update Stocks set Ask=#Ask, Bid=#Bid, PreviousClose=#PreviousClose, CurrentOpen=#CurrentOpen Where Name=#Name", con);
cmd.Parameters.AddWithValue("#Name", textBox1.Text);
cmd.Parameters.AddWithValue("#Ask", textBox2.Text);
cmd.Parameters.AddWithValue("#Bid", textBox3.Text);
cmd.Parameters.AddWithValue("#PreviousClose", textBox4.Text);
cmd.Parameters.AddWithValue("#CurrentOpen", textBox5.Text);
con.Open();
int a = cmd.ExecuteNonQuery();
if (a > 0)
{
MessageBox.Show("Data Updated");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
con.Close();
}
}
Change the code to suit your needs.

How can I avoid duplicate items in a checkListBox

I am working on my windows form application using c#. I have a checkListBox that is binded to db. I am wondering is there a way to delete any duplicate record from the database?
Here is my code
private void fill_checkListBox()
{
try
{
string query = "select * from table_1 ";
SqlCommand myTeacherCommand = new SqlCommand(query, myConn);
//reading the value from the query
dr = myCommand.ExecuteReader();
//Reading all the value one by one
teacherCB.Items.Clear();
while (dr.Read())
{
string name = dr.IsDBNull(2) ? string.Empty : dr.GetString(2);
teacherCB.Items.Add(name);
if (!checkBox.Items.Contains(name))
{
teacherCB.Items.Add(name);
}
}
dr.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
The first answer - use DISTINCT in query:
select distinct * from table_1
Also, I advice you to specify column names in query:
select distinct ID, Name from table_1
But I don't know anything about your data in table.

Simple way to check how many rows I have in my database

I'm connected to a database through the SqlConnection class. Is there any simple why to check how many rows are in the database or do I have to create a SqlDataReader and increment till the last row in it ?
I assume "rows in the database" actually means "rows in the table".
You should use Count and SqlCommand.ExecuteScalar:
int rowCount = 0;
using(var con = new SqlConnection(connectionsString))
using (var cmd = new SqlCommand("SELECT COUNT(*) FROM dbo.TableName", con))
{
try
{
con.Open();
rowCount = (int) cmd.ExecuteScalar();
} catch (Exception ex)
{
// log this exception or do something else useful, otherwise it's better to...
throw;
}
}

Sql Server CE - Temporary disable auto increment on a specific column

I have this little question that's been on my mind for a while now.
Here it goes:
Is it possible to temporary disable the Auto_Increment on the column ID.
So that I can add a new row to the table and being able specify the ID value when inserting the row.
And then in the end enable the Auto_Increment again, and let do its work as usual?
And if its possible how can I do it?
The table structure is very simple
Column name (attributes)
ID (Primary Key, Auto Increment, int, not null)
Name (nvarchar(100), not null)
Note:
The table name is: People.
Let's also consider that the table already has data and cannot be changed.
The database server is SQL Server CE.
The SQL commands will be executed in a C# program, if it's of any help.
I really hope its possible, it would come very handy.
Thanks
EDIT
SqlActions SqlActions = new SqlActions();
SqlCeCommand SqlCmd = new SqlCeCommand("SET IDENTITY_INSERT People ON", SqlActions.Connection());
try
{
SqlCmd.ExecuteNonQuery();
}
catch (SqlCeException Error)
{
Console.WriteLine(Error.ToString());
}
string query = "INSERT INTO People SET (ID, Nome) VALUES (#ID, #Nome)";
SqlCeCommand SqlInsert = new SqlCeCommand(query, SqlActions.Connection());
SqlInsert.Parameters.AddWithValue("#ID", 15);
SqlInsert.Parameters.AddWithValue("#Nome", "Maria");
try
{
SqlInsert.ExecuteNonQuery();
}
catch (SqlCeException Error)
{
Console.WriteLine(Error.ToString());
}
The connection string is working, I have tried it.
He reports:
There was an error parsing the query.
[ Token line number = 1,Token line
offset
= 20,Token in error = SET ]
SOLUTION thanks to OrbMan
SqlActions SqlActions = new SqlActions();
SqlCeCommand SqlCmd = new SqlCeCommand("SET IDENTITY_INSERT People ON", SqlActions.Connection());
try
{
SqlCmd.ExecuteNonQuery();
string query = "INSERT INTO People (ID, Nome) VALUES (#ID, #Nome)";
SqlCmd.CommandText = query;
SqlCmd.Parameters.AddWithValue("#ID", 15);
SqlCmd.Parameters.AddWithValue("#Nome", "Vania");
SqlCmd.ExecuteNonQuery();
}
catch (SqlCeException Error)
{
Console.WriteLine(Error.ToString());
}
I believe you can use SET IDENTITY_INSERT. I am not sure if this works in all versions.
Update 2:
Try this version:
SqlActions SqlActions = new SqlActions();
SqlCeCommand SqlCmd = new SqlCeCommand("SET IDENTITY_INSERT People ON", SqlActions.Connection());
try
{
SqlCmd.ExecuteNonQuery();
string query = "INSERT INTO People (ID, Nome) VALUES (#ID, #Nome)";
SqlCmd.CommandText = query;
SqlCmd.Parameters.AddWithValue("#ID", 15);
SqlCmd.Parameters.AddWithValue("#Nome", "Maria");
SqlCmd.ExecuteNonQuery();
}
catch (SqlCeException Error)
{
Console.WriteLine(Error.ToString());
}

Categories