how to check the duplicate entry in sql - c#

Design of SQL Table Users:
Columns:
ID(Primary Key),
Name,
Age,
Zip.
I am displaying a grid view onto the asp.net application with the above table details which i am able to do now.Right now i am displaying only Name,age,zip on to the gridview.There is a form below the gridview where user can enter the data and save back to the DB.Here i am able to enter name,age,zip to the database and i am able to see the changes in the gridview.
So when i enter a duplicate name its not saving to the database as expected,at this point i have to show some thing to the user that the name already exists .
Here is my code in c#:
try
{
param[0] = new SqlParameter("#Name", SqlDbType.NVarChar);
param[0].Value = txtName.Text;
param[1] = new SqlParameter("#Age", SqlDbType.NVarChar);
param[1].Value = txtAge.Text;
param[2] = new SqlParameter("#Zip", SqlDbType.int);
param[2].Value = txtZip.Text;
DBHelper helper = new DBHelper();
helper.ExecuteNonQuery(CommandType.StoredProcedure, "Add_Users", param);
GridView1.DataBind();
}
catch (Exception ex)
{
}
I am expecting an sql exception in the above code where i am planning to notify the user .But i am unable to get any exception .
Can some one suggest where i am missing the catch here.
I just want to notify the user that the name is already taken eventually.

Using exceptions is a bad design in this case. This is not an error, but a predictable behaviour of your program.
One of the easiest ways to solve the problem is doing a select at the end of the Add_Users stored procedure that returns 1 or 0, depending on the success or failure, and using ExecuteScalar insead of ExecuteNonQuery to get the result.
You can also use a return in the stored procedure, and take back that value (geenrally as a special output parameter), but I don't know if the DbHelper allows you to do so.

You might also want to post your SQL code for "Add_Users".
I would think about doing a validation step rather than attempting to add it. So have one Stored Procedure for validation were you check the number of rows that contain the name you are trying to add. If the count is zero then proceed with the add. If there are records with that name then display a message to the user.

In your DBHelper use count to determine if your db should commit or not :
int count = SELECT COUNT(column_name) FROM table_name
and return it to your method which can then test it (instead of using Try/Catch)
if (helper.ExecuteNonQuery(CommandType.StoredProcedure, "Add_Users", param) >0))
{
// Show Error
}else
{
// all ok
}

Related

Use Value of ASP.NET TextBox in SQL SELECT Query

Im looking at ASP.NET and I want to be able to use a value that a user types in a TextBox in a SELECT query to get that record.
For example, user types "1234" in the TextBox, and the SQL SELECT query gets the record with primary key value "1234" from the database and displays it on the page. Is this possible (programmatically or not)? Im using C# for my ASP.NET site as well. If you could point me in the right direction I'd really appreciate it.
Here is a sample code snippet to get you started. Basically, you establish the connection and supply the textbox.Text value into the command's Parameters collection.
using (SqlConnection thisConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["YourSQLConnectionString"].ConnectionString))
{
SqlCommand queryCommand = thisConnection.CreateCommand();
try
{
// Open Connection
thisConnection.Open();
queryCommand.CommandText = #"select * from [YourTable] where id = #id";
queryCommand.Parameters.AddWithValue("#id", this.ID.Text);
SqlDataReader dr = queryCommand.ExecuteReader();
if (dr.Read())
this.message.Text = dr["id"].ToString();
else
this.message.Text = "ID not found";
}
catch (Exception ex)
{
this.message.Text = ex.Message;
}
}
}
You need an ORM (Object Relational Mapper) like Entity Framework, Dapper ..etc. To map your objects (in your application) with the database objects (tables, views, sp ..etc.). Then, you can (from your application) query your database, update, delete, insert operation.
Then, from your code behind, you can get the selected value, and use ORM to process that value on the database.
This is basically what you need. The rest is a learning curve !

What NpgsqlDbType should be used to clear "Can't write CLR type" error

I am using PostgreSQL as my database. I have an application that is written in
ASP.NET
C#
WebForms
Using Npgsql with PostgreSQL
I have table named tblAppt in my database, in that table I have a column named appttime that column's Data type is time without time zone
In pgAdmin4's Query Tool if I run the following query:
INSERT INTO tblAppt (appttime) VALUES ('00:30:00');
The results are:
INSERT 0 1 Query returned successfully in 105 msec.
Which means the record was added in my table, in the image you can see I have a row:
Now in my web application I have a text box named txtCustTime, in that text box I enter this value 00:30:00
When I press the submit button I get the following error:
System.InvalidCastException Can't write CLR type System.String with
handler type TimeHandler
Here is a snippet of what happens on the submit:
string insertstmt = "INSERT INTO tblAppt(appttime) VALUES (#ApptTime)";
NpgsqlCommand cmd = new NpgsqlCommand (insertstmt, con);
cmd.Parameters.Add("#ApptTime", NpgsqlDbType.Time );
cmd.Parameters ["#ApptTime"].Value = txtCustTime.Text;
con.Open ();
cmd.ExecuteNonQuery ();
con.Close ();
My question is do I need to cast it because the values in a textbox or use a different datatype, or something else.
PLEASE NOTE: I have other columns in that table that are not time or dates and they submit fine. My problem seems to be specifically to this particular column type.
Additional NOTE:
If I run this on submit the value is added to the database:
string insertstmt = "INSERT INTO tblAppt(appttime) VALUES ('00:30:00')";
NpgsqlCommand cmd = new NpgsqlCommand (insertstmt, con);
con.Open ();
cmd.ExecuteNonQuery ();
con.Close ();
Which tells me my problem I am not understanding has something to do with the parameter.
The folks in the comments were correct in that TimeSpan is the way to go. However the documentation was not very clear on how to use it.
The correct way to use TimeSpan for the problem above is:
string insertstmt = "INSERT INTO tblAppt(appttime) VALUES (#ApptTime)";
NpgsqlCommand cmd = new NpgsqlCommand (insertstmt, con);
TimeSpan thetime = TimeSpan.Parse(txtCustTime.Text);
cmd.Parameters.Add("#ApptTime", NpgsqlDbType.Time );
cmd.Parameters["#ApptTime"].Value = thetime;
con.Open ();
cmd.ExecuteNonQuery ();
con.Close ();
I used this link as a reference:
https://learn.microsoft.com/en-us/dotnet/api/system.timespan?redirectedfrom=MSDN&view=netframework-4.7.2

Inserting only new data to SQL Table

Right now I have a SQL Server Table that's populated with data from external .CSV file that gets updated occasionally by having new data appended to it. Originally I had my program set up to delete everything in the table every time its ran and it would upload everything from the .CSV file. Now I'm trying to reconfigure it so that it only inserts newly appended data from the file instead of deleting everything first.
The program works by first delimiting data from the .CSV file that gets uploaded to array. Then I basically go through the array and upload each element. Right now I have secondary array that contains all the current primary keys from the Table and so far I have tried to compare these to the ones in the .CSV file that's being read. So it checks if the the primary key from the .CSV file is not already in the table / secondary array it goes ahead and does the inserting. This seems like a sound logic to be but for some reason I can't get it to work.
Here is the meat of my code:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
//Create new SQL connection and adapter using Windows Authentication
SqlConnection myConnection = new SqlConnection("Data Source=database; Initial Catalog=Dashboard; Integrated Security=SSPI; Persist Security Info=false; Trusted_Connection=Yes");
SqlDataAdapter da = new SqlDataAdapter();
try
{
myConnection.Open();
da.InsertCommand = new SqlCommand("INSERT INTO DashboardLibAnswer(Id,Date,Time,Question,Details,Answer,Notes,EnteredBy,WhereReceived,QuestionType,AnswerMethod,TransactionDuration)"
+ "VALUES(#Id,#Date,#Time,#Question,#Details,#Answer,#Notes,#EnteredBy,#WhereReceived,#QuestionType,#AnswerMethod,#TransactionDuration)", myConnection);
da.InsertCommand.Parameters.Add("#Id", SqlDbType.NVarChar);
da.InsertCommand.Parameters.Add("#Date", SqlDbType.Text);
da.InsertCommand.Parameters.Add("#Time", SqlDbType.Text);
da.InsertCommand.Parameters.Add("#Question", SqlDbType.Text);
da.InsertCommand.Parameters.Add("#Details", SqlDbType.Text);
da.InsertCommand.Parameters.Add("#Answer", SqlDbType.Text);
da.InsertCommand.Parameters.Add("#Notes", SqlDbType.Text);
da.InsertCommand.Parameters.Add("#EnteredBy", SqlDbType.NVarChar);
da.InsertCommand.Parameters.Add("#WhereReceived", SqlDbType.NVarChar);
da.InsertCommand.Parameters.Add("#QuestionType", SqlDbType.NVarChar);
da.InsertCommand.Parameters.Add("#AnswerMethod", SqlDbType.NVarChar);
da.InsertCommand.Parameters.Add("#TransactionDuration", SqlDbType.NVarChar);
//Using the global variable counter this loop will go through each valid entry and insert it into the specifed database/table
for (int i = 0; i < counter; i++)
{
//This is where I try to do the comparision.
//idS is the secondary array with all the current primary keys in the Table
//collection is the primary array that stores new data from the .CSV file
if (idS.ElementAt(i) != collection.getIdItems(i))
{
da.InsertCommand.Parameters["#Id"].Value = collection.getIdItems(i);
da.InsertCommand.Parameters["#Date"].Value = collection.getDateItems(i);
da.InsertCommand.Parameters["#Time"].Value = collection.getTimeItems(i);
da.InsertCommand.Parameters["#Question"].Value = collection.getQuestionItems(i);
da.InsertCommand.Parameters["#Details"].Value = collection.getDetailsItems(i);
da.InsertCommand.Parameters["#Answer"].Value = collection.getAnswerItems(i);
da.InsertCommand.Parameters["#Notes"].Value = collection.getNotesItems(i);
da.InsertCommand.Parameters["#EnteredBy"].Value = collection.getEnteredByItems(i);
da.InsertCommand.Parameters["#WhereReceived"].Value = collection.getWhereItems(i);
da.InsertCommand.Parameters["#QuestionType"].Value = collection.getQuestionTypeItems(i);
da.InsertCommand.Parameters["#AnswerMethod"].Value = collection.getAnswerMethodItems(i);
da.InsertCommand.Parameters["#TransactionDuration"].Value = collection.getTransactionItems(i);
da.InsertCommand.ExecuteNonQuery();
}
//Updates the progress bar using the i in addition to 1
_worker.ReportProgress(i + 1);
} // end for
//Once the importing is done it will show the appropriate message
MessageBox.Show("Finished Importing");
} // end try
catch (Exception exceptionError)
{
//To show exceptions thrown just uncomment bellow line
//rtbOutput.AppendText(exceptionError.ToString);
} // end catch
//Closes the SQL connection after importing is done
myConnection.Close();
} // end backgroundWorker1_DoWork
Right now the program executes but no new data is being inserted. It seems that program does not get out of the for loop because if it runs successfully it shows the "Finished Importing" message box.
The line
if (idS.ElementAt(i) != collection.getIdItems(i))
looks odd. Depending on what the getIdItems return, it looks to me as if you will match the first time the two lists are out of synch - so if items don't appear in the exact same order as you have already persisted them, you may get a false positive. Ie. the code will evaluate that the item doesn't exist and should be persisted, even if it exists at some other place in your collection.
Then, if you have a unique constraint the insert will fail, send you to the exception handler that is commented out - and then exit.
The first thing I would do would be to activate the exception handler to know what was going on. Second, I would probably change the code above so that you lookup, rather than iterate through, your idS collection. Ie. if you make idS a list or you include the Linq extension methods, you could do:
if (!idS.Contains(collection.getIdItems(i))
EDIT: Do note that for large idS, this is not particularly efficient and doesn't scale very well as your list grows. If you expect to handle a large number of idS, you might want to change the list to be a hash-collection or use the solution suggested here Check if list<t> contains any of another list.

Catching specific exception while inserting data in acces database

I am inserting data into access databse and if the data is already present i.e. duplicate enty found then just need to update that enty.
public bool InsertInToTooltip()
{
InitializeSettingsDatabase();
OleDbCommand command;
command = new OleDbCommand(//Query, settingsDbConn);
try
{
command.ExecuteNonQuery();
}
catch (Exception e)
{
UpdateTable();
}
CloseDatabase();
return true;
}
Is there any specific exception thrown in case of inserting duplicate entries in acces database?
You should check if the record exists and the issue an insert or update rather than using an exception for this. You could wrap that logic in a stored procedure or do a select the an additional query.
All in one
IF EXIST (select true from table where id = #id)
Update table set x = y
Else
Insert into table (x, y) values ('x', 'y')
Try using a DataAdapter if you are using controls such as DataGridViews, ComboBoxes etc... This will automatically do all the handling for you as long as you link it to a database source and control. Otherwise i would rather do an extra sql statement that will check if the data is available in the database e.g.
SELECT * FROM TABLE WHERE COLUMN = _VAR
Based on what it returns you can either INSERT or Update. I hope this helps.

how to compare elements in a string with the database table values

In my project i have to give a string input through a text field, and i have to fill a database table with these values. I should first check the values of a specific table column, and add the input string only if it is not there in the table already.
I tried to convert the table values to a string array, but it wasn,t possible.
If anyone have an idea about this, your reply will be really valuable.
Thankx in advance.
Since you say your strings in the database table must be unique, just put a unique index on that field and let the database handle the problem.
CREATE UNIQUE INDEX UIX_YourTableName_YourFieldName
ON dbo.YourTableName(YourFieldName)
Whenever you will try to insert another row with the same string, SQL Server (or any other decent RDBMS) will throw an exception and not insert the value. Problem solved.
If you need to handle the error on the front-end GUI already, you'll need to load the existing entries from your database, using whatever technology you're familiar with, e.g. in ADO.NET (C#, SQL Server) you could do something like:
public List<string> FindExistingValues()
{
List<string> results = new List<string>();
string getStringsCmd = "SELECT (YourFieldName) FROM dbo.YourTableName";
using(SqlConnection _con = new SqlConnection("your connection string here"))
using(SqlCommand _cmd = new SqlCommand(getStringsCmd, _con)
{
_con.Open();
using(SqlDataReader rdr = _con.ExecuteReader())
{
while(rdr.Read())
{
results.Add(rdr.GetString(0));
}
rdr.Close();
}
_con.Close();
}
return results;
}
You would get back a List<string> from that method and then you could check in your UI whether a given string already exists in the list:
List<string> existing = FindExistingValues();
if(!existing.Contains(yournewstring))
{
// store the new value to the database
}
Or third option: you could write a stored procedure that will handle the storing of your new string. Inside it, first check to see whether the string already exists in the database
IF NOT EXISTS(SELECT * FROM dbo.YourTableName WHERE YourFieldName = '(your new string)')
INSERT INTO dbo.YourTableName(YourFieldName) VALUES(your-new-string-here)
and if not, insert it - you'll just need to find a strategy how to deal with the cases where the new string being passed in did indeed already exist (ignore it, or report back an error of some sorts).
Lots of options - up to you which one works best in your scenario!

Categories