I have an entity with code field. For each user that uses this entity, each entity the user insert must have code. So I wrote code that do the following logic:
1. if the user set the code field - then use his code.
2. if the user doesn't set the code field - read from the db the next serial code (starting from 1, searching the next serial code that doesn't already exists) and use this code.
The probelm is scenario like this:
Assuming the user have the ability to add two entities in single mouse click.
Assuming the next serial code should be "5".
In the first entity the user set code=5 and in the second entity the user doesn't set the code.
Because I am using the entity framework and there is one commit/save changes at the end of the logic, I Insert the first entity (the one with code=5) and for the second entity, searching the db for the next next serial code that doesn't already exists. The next serial code that doesn't already exists in the database is "5". So I set the second entity the code "5".
Eventually I came up with two entities with code=5 which is wrong.
I thought of ways to solve it.
One way is to do SaveChanges right after storing the first entity but this might make many calls to the db, and I am not sure for this solution.
Another way is to search in the DB and in the attached objects but I really don't know how to do it.
Does anyone has any better idea?
You can use an IDENTITY column to allow SQL Server to auto-populate it when the user doesn't specify one, and when you have one that they do specify you just put it in your INSERT/UPDATE query along with the other fields. It will save your value instead of creating a new one. You do need to check and make sure that the ID hasn't already been used before doing that if you have a unique constraint on that field or if you don't want to allow duplicates when the user specifies a value.
The following example uses a table called MyTable with 3 columns (ID int IDENTITY, FIRST_NAME varchar, LAST_NAME varchar). I would recommend using parameters instead of passing the values in the sql string as I did below since this was just an example and it was faster to put together that way.
String sSQL = "";
String sFields = "";
String sValues = "";
String sCode = "";
// sCode = ... (get user entered code)
String sFirstName = "John";
String sLastName = "Doe";
if (sCode != "")
{ //Add the user specified value and field for the identity column to the SQL
sFields = "ID, ";
sValues = sCode + ", ";
}
sFields += "FIRST_NAME, LAST_NAME";
sValues += "'" + sFirstName.Replace("'","''") + "', '" + sLastName.Replace("'","''") + "'";
sSQL = "INSERT INTO MyTable (" + sFields + ") VALUES (" + sValues + ")"
//execute the sql statement
Related
I am trying to implement an Enum within a Save button (which inserts new records in a DB connected to the Visual Studio WinForms Application).
In this case, I have Books & Category Tables. Category is also a Foreign Key within Books table (as CategoryID, which should accept only int data type).
With that said, I would like the application to understand / convert a string value to an int value, for example:
If I input the value "History" within the Category Textbox in the application, and fill in the rest of the details required to insert a new book record in DB, and finally click Save Button, I need the application to understand that "History" would reflect an ID (in this case, ID: '4') in Category Table.
In short, I don't want to input int values in the application - I want to type in the Category Name in the CategoryID Textbox.
private void btnSave_Click(object sender, EventArgs e)
{
string ConnectionString = #"Data Source=.\SQLEXPRESS;AttachDbFilename=
C:\Program Files\Microsoft SQL
Server\MSSQL14.SQLEXPRESS\MSSQL\DATA\Library System Project.mdf
;Integrated Security=True;Connect Timeout=30";
string Query = "insert into Books (BookName, BookAuthor, CategoryID, ClassificationID, BookAvailabilityQuantity, Price) values ('" + this.txtName.Text.Trim() + "','" + this.txtAuthor.Text.Trim() + "','" + this.txtCategory.Text.Trim() + "','" + this.txtClassification.Text.Trim() + "','" + this.txtAvailabilityQuantity.Text.Trim() + "','" + this.txtPrice.Text.Trim() + "');";
SqlConnection DBCon = new SqlConnection(ConnectionString);
SqlCommand DBCommand = new SqlCommand(Query, DBCon);
SqlDataReader DBReader;
try
{
DBCon.Open();
DBReader = DBCommand.ExecuteReader();
MessageBox.Show("New book record added to the system.", "Library System", MessageBoxButtons.OK);
while (DBReader.Read())
{
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
// *** If you're going to be opening a connection be sure to close it ***
// *** Finally blocks work well for this ***
DBCon.Close();
this.txtName.ResetText();
this.txtAuthor.ResetText();
this.txtCategory.ResetText();
this.txtClassification.ResetText();
this.txtAvailabilityQuantity.ResetText();
this.txtPrice.ResetText();
}
}
Create an enum for your categories, for example:
enum BookCategory
{
Science=1,
Art,
Romance,
History
}
Then you can write:
if(Enum.TryParse<BookCategory>(txtCategory.Text.Trim(), out BookCategory categoryId))
Console.WriteLine((int)categoryId);
else
Console.WriteLine("Category not recognised");
Which will print 4 if txtCategory contains "History".
If I understand your question correctly, there are different approaches for what you're trying to achieve.
Where do you want that 'enum' to originate from? You can actually make an enum with categories and their respectable value, and display it to the user to chose from, like:
public enum Categories
{
SciFi = 1,
...
History = 4,
...
}
as iakobski answered, and you can also get these categories from a database (thus, making them dynamic, e.g. you can add and remove categories from the list without the need to change static code, compile it and re-deploy).
Usually, the common practice in most cases is indeed storing such values in a database, in a table with columns of an ID and CategoryName.
If I input the value "History" within the Category Textbox in the
application, and fill in the rest of the details required to insert a
new book record in DB, and finally click Save Button, I need the
application to understand that "History" would reflect an ID (in this
case, ID: '4') in Category Table.
Unless you have business rules tied to specific emum values, I suggest to don't hard-code the values in the application and instead load the category name and id values from a database Category table. That can also ensure data integrity with a foreign key relationship to the Book table and allow new categories to be added without code changes.
A better user experience would be a combobox/list that the users to select from by name instead of free-form text box. The code can then use the id of the selected value without additional validation or lookup for the insert and the database.
On a separate note, use parameterized queries to improve performance and security. One should never build SQL queries using string concatenation from untrusted sources.
I want to generate unique ID's for clients and store them in MySql database. It's a C# winform application, when one client enter his data like name etc. and when clicking on savebutton the ID generator needs to give him an unique ID which won't be repeated later.
I made it work, but after about 30 inserts, the generator drops a repeated number and the MySql gives this error: "Duplicate entry '76' for key 'PRIMARY'".
This is not a big error or crash, but can be annoying for long time use.
That's my code:
int minID = 1;
int maxID = 1000;
int resID;
Random CustomID = new Random();
resID = CustomID.Next(minID,maxID);
How can I check the saved ID's and clear the repeating first, then generate another number that's unique and not in the table yet?
MySql info (database table:ugyfelinfo, column: ID)
auto_increment works well, but with my method I was able to show to saved ID to the customer when he clicked save button. Like this:
MessageBox.Show("New Costumer ID: " + resID + " - Saved in Database!")
But, now because I have auto_increment in mysql, how can I display the delivered ID for user via MB?
The queries are like this:
string constring = "datasource=localhost;port=3306;username=root;password=root";
string Query = "insert into clients_db.ugyfelinfo (Ugyfel,... ) " +
" values('" + this.UgyfelTextBox.Text + "','" ..."') ;";
MySqlConnection conDataBase = new MySqlConnection(constring);
MySqlCommand cmdDataBase = new MySqlCommand(Query, conDataBase); etc.
And I tried something like this this:
string idquery = "SELECT from clients_db.ugyfelinfo (LAST_INSERT_ID();) ";
MessageBox.Show("New user ID: "+idquery+" saved in database!");
Probably the best solution is to use Guid.NewGuid() and save it into CHAR(16) column (see this post). Chance of duplicate entry is very close to zero and even if you have a bad luck and Guid.NewGuid() generates duplicate, you can re-run your insert with new value.
If you don't need your identifier to be globally unique or you need integer key, you have to transfer responsibility for ID generating to the database. You just insert new row without the id value and you query for the result. This post migh help you.
If you have single database then maybe use database generate unique id is better.
The code you showing there is no warranty it wont get duplicated.
If you want client side unique code without checking the database have a look at using GUID.
I have a problem while reading from SQL Server in C#. It is happening in SSIS, I have inserted a C# script in data flow.
I am using the code below:
using (SqlConnection connection = new SqlConnection(connectionString))
{
string vendorName = Row.VendorName.ToString().Substring(0,1).ToUpper() + Row.VendorName.ToString().Substring(1);
using (SqlCommand command = new SqlCommand("Select TOP 1 * from Logs where MessageId = '" + Row.id.ToString() + "'" +
"AND name = (Select Id from Names where vendor_name = '" + vendorName +
"order by CreatedDate desc", connection))
{
connection.Open();
string status = "";
using (SqlDataReader oReader = command.ExecuteReader())
{
while (oReader.Read())
{
status = oReader["Status"].ToString();
}
}
if (String.IsNullOrEmpty(status))
{
SaveDataToDB(Row.id, Row.VendorName, "Unknown");
}
}
}
In the Logs table, there are about 10000 rows, and the related datasource, where Row data belongs to, has around 9000 records. The problem is that, even though the query is working well, in the script it sometimes brings status value as null, because it cannot find the record in the SQL. I am getting the query and copy/pasting it to SQL, executing the query brings result there, but not in C# somehow. For example, I am running the C# two times in sequence, at the first time it says Status is null for the id: 354456, but when I run it at the second time it finds 354456 correctly but saying that status of 354499 is null.
Any idea for me to solve this issue? I really appreciate for any help.
According to me, this could be due to order of evaluation of user defined values embedded within the query. Could be the first dynamic value might be evaluated before the one in the inner query.
As I am not sure about the value to variable binding, however, I would recommend you to check following points;
a) externalise both your variable (vendor name and row id) outside and evaluate and ensure it has respective values
b) and then form your query statement with the evaluated values
May be you can debug and see the CommandText of command object just before call Execute.
your code is really inefficient, you should cache vendorname in a string and do all the substring operations on that.
for example:
string vendorName = Convert.ToString(Row.VendorName);
vendorName = vendorName.Substring(0,1).ToUpper() + vendorName.Substring(1);
instead of selecting all the columns, select the specific column for a speed up select Status from.
try to debug your code first, see which id you are getting and what is the result of your query.
its really hard to debug your code without any debug information.
change your code to this (Select Id from Names where vendor_name = '" + vendorName + "')" and put a blank space next to every " character e.g. " AND instead of "AND
I have to create logic for generation unique number identifier for records in database. id, generated in database is a separate column.
At this moment, when user calls "create record" action, I save new record, get its database id, generate record number using this id, then put it to the edit form.
Using this way means that all entity fields should be nullable to save record to database.
I don't like this way. I know that should be better way.
Is there a better practice to generate unique number identifier? What is possibility of generating non-unique random numbers?
Thank you
The pattern that you're using, of saving an empty record simply to get the ID, is not a good one.
The standard approach, and the one that I'd recommend, is for Create Record to simply display an empty form (the ID at this point will typically be 0). The user fills in the form and the data is only committed to the database when the user clicks Save. The ID should be an IDENTITY column.
A problem with your approach is that if users do not complete the form, you end up with lots of incomplete records in your database. And, of course, it makes it much more difficult to handle data validation and integrity.
An alternative approach, if you really must display the ID to the user, is to have a separate table containing a row with a "Next Record ID" column. This column can be incremented and returned as an atomic operation and used to populate the ID of your new record. You still don't create the real record, just increment this "Next Record ID" in your Create Record action. Using this approach, you can use the same approach for multiple entities by having separate rows for each in this "Record IDs" table. Bear in mind that if the user does not ultimately save the record to the database, an ID will still have been 'used up'. The numbers will still be unique and will be chronological but won't necessarily be contiguous.
I don't get it, but, if you are using the uniqueidentifier data type in your database, that translates to Guid in C#, so you can do:
public Guid CreateRecord(MyObject model) {
Guid newId = Guid.NewGuid();
MyTable tbl = new MyTable();
tbl.guid = newId;
// ... other columns
db.MyTable.AddObject(tbl);
db.SaveChanges();
return newId;
}
though what I normally do, is having the PrimaryKey as int and add a uniqueidentifier field named guid (that I use it publically instead the column_id) and remember to index that column.
Code for Table..
CREATE TABLE TblTransactions(
TId varchar(8),
TName varchar(50)
)
C# Code Behind…
protected void Page_Load(object sender, EventArgs e)
{
string id = GenerateId("TblTransactions", "TId", 8, "TRN");
// insert the id along with data in the table
Response.Write(id);
}
public string GenerateId(string TableName, string ColumnName, int ColumnLength, string Prefix)
{
SqlConnection con = new SqlConnection("server=.;integrated security=true;database=EBissCard");
string Query, Id;
int PrefixLength, PadLength;
PrefixLength = Convert.ToInt32(Prefix.Length);
PadLength = ColumnLength - PrefixLength;
Query = "SELECT '" + Prefix + "' + REPLACE(STR(MAX(CAST(SUBSTRING(" + ColumnName + "," + Convert.ToString(PrefixLength + 1) + "," + PadLength + ") AS INTEGER))+1," + PadLength + "),' ',0) FROM " + TableName;
SqlCommand com = new SqlCommand(Query, con);
con.Open();
if (com.ExecuteScalar().ToString() == "")
{
Id = Prefix;
for (int i = 1; i <= PadLength - 1; i++)
{
Id += "0";
}
Id += "1";
}
else
{
Id = Convert.ToString(com.ExecuteScalar());
}
con.Close();
return Id;
}
An idea to generate a unique number for a record is to use the time() in milliseconds (since a reference point of time, say, 01/01/2010).
However, if there are 2 records that are simultaneously getting updated, this may cause an issue. To solve this problem, if each of the user can be assigned a number (when creating the userID), a combination (concatenation) of that "user number" and time in milliseconds will give you the unique number you need.
Try the Random class from .net itself.
I have two tables one is members table with columns member id , member first name, member last name. I have another table guest passes with columns guest pass id and member id and issue date .
I have a list view that will displays guest passes details (I.e) like member name and issue date and I have two text boxes those are for entering member name and issue date .
member name text box is auto complete text box that working fine....
but the problem is when I am entering the name that is not in member table at this time it will accept and displays a blank field in list view in member name column and member id is stored as "0" in guest pass table ......
I don't want to display the member name empty blank and I don t want to store "0" in guest pass table
and this is the insert statement
sql2 = #"INSERT INTO guestpasses(member_Id,guestPass_IssueDate)";
sql2 += " VALUES(";
sql2 += "'" + tbCGuestPassesMemberId.Text + "'";
sql2 += ",'" + tbIssueDate.Text + "'";
guestpassmemberId = memberid
is there any validation that need to be done
and this is the auto complete text box statement
sql = #"SELECT member_Id FROM members WHERE concat(member_Firstname,'',member_Lastname) ='" + tbMemberName.Text+"'";
dt = GetData(sql, mf);
if (dt != null)
{
if (dt.Rows.Count > 0)
{
tbCGuestPassesMemberId.Text = Convert.ToInt32(dt.Rows[0] ["member_Id"]).ToString();
}
}
can any one help me on this ...
is there any type of validation with sql query
pls help me .....
You can validate the values before passing them to the INSERT. Additionally you can also set a constraint to validate versus a regular expression in SQL.
SQL constraints
To validate before inserting you should have something like this:
private void validateData(Long memberId) {
//Pseudo code Depends on how you are connecting to your database...
SQLQuery query = getQuery("existsMemberId");
query.setParameter("memberId");
executeQuery(query);
// If the query returns something then the reference exists and it is ok to proceed
}
In the file you are storing your queries...
#existsMemberId
select 1
from members mem
where mem.id = :id <-- parameter
Additionally you should make foreign key constraint between members and guest passes with ID as the foreign key:
ALTER TABLE GuestPasses
ADD CONSTRAINT fk_memberId
FOREIGN KEY (id)
REFERENCES Members(id)