Cannot insert duplicate key row in object with unique index 'in_name' - c#

I get this error: Cannot insert duplicate key row in object with unique index 'in_name'
What can be the problem?
var ing = (from x in db.tblTable where x.ing_name == ing_name select x);
var ing1 = ing.First();
ing1.ing_name = ing1.ing_name + " (" + FormatC(ing_brand) + ")";
db.SaveChanges();
And here is FormatC:
public static string FormatC(string str)
{
if (!string.IsNullOrEmpty(str))
return str.Substring(0, 1).ToUpper() + "" + str.Substring(1).ToLower();
else
return "";
}

Got this answer from - https://www.sqlservercentral.com/forums/topic/cannot-insert-duplicate-key-row-in-object-with-unique-index-on-duplicate-foreing-key
Turns out that SQL Server, by default, sets indexed fields to allow only unique values. To check this, open the table in Design and select "Manage Indexes and Keys" option. Select the index/key listed and check the appropriate Yes/No drop down for the "Is Unique" property.

Related

SQL How to replace a value

I'm using a Database I was able to get all the data from the database and save it in a List<>. I made changes in the List<> using a DataGrid and now I want to replace each Database value for the List<> values WHERE the List.ID == Database ID. I use Dapper (In case it matters);
public void SetData(List<DatabaseInfoModel> database)
{
using (IDbConnection connection = new System.Data.SqlClient.SqlConnection("Server=.\\SQLEXPRESS; Database=XXXX; User Id=XXXX; Password=password;"))
{
foreach(DatabaseInfoModel item in database)
{
connection.Execute($"UPDATE DataTable " +
$"SET Name = {item.Name}, " +
$" Description = {item.Description}, " +
$" Record = {item.Record} " +
$" WHERE ID = {item.ID}");
}
}
}
you can pass a model, ex
.Execute("update mydogs set age=#Age where id=#Id",dog);
"dog" is your model
UPDATE DataTable
SET
Name = REPLACE(Name, item.Name, 'Replacement Value')
.
.
WHERE ID = {item.ID}
Is this what you are looking for ?
In case you are looking for the syntax, here is more information:
https://learn.microsoft.com/en-us/sql/t-sql/functions/replace-transact-sql?view=sql-server-ver15

altering table to add unique columns sql ce

I'm trying to add a column on my table using SQL Compact Edition. It used to work before but I am getting an error now that says
A duplicate value cannot be inserted into a unique index. [ Table name = final try,Constraint name = UQ__final try__0000000000000228 ]
i'm using C# because i am getting the new column name (using textbox) and determine if the column is unique(checkbox). it used to work then suddenly it isn't. please help! my code is kinda messy. i'm sorry here it is:
string constr = "ALTER TABLE ";
if (textBox2.Text.ToString() != "")
{
constr += "[" + table + "] ADD [" + col1 + "]";
if (comboBox2.Text == "text")
{
constr += " nvarchar(300)";
}
else if (comboBox2.Text == "number")
{
constr += " int";
}
else if (comboBox2.Text == "date")
{
constr += " datetime";
}
if (checkBox1.Checked)
{
constr += " unique";
}
}
cmd.CommandText = constr;
cmd.ExecuteNonQuery();
The constr outputs something like
ALTER TABLE table ADD COLUMN column1 int unique
Please help! Thanks!
EDIT:
I discovered I cannot add a column only if the data grid view already have its data inside. What should I do? Help! Thanks!!!
I am not familiar with sql server ce but in normal sql server creating a column with the unique keyword means creating an index where no 2 rows can have a null in it because than they are not unique.
So you need to create your column without the unique keyword and than afterwards create an unique index that allows null.
You can create an unique index that ignores null values like this :
CREATE UNIQUE NONCLUSTERED INDEX idx_col1
ON dbo.MyTable(col1)
WHERE col1 IS NOT NULL;

using foreach to access a list

I am using a foreach loop to access the values of objects(of type Meal) stored in a list. Then I am calling a database query to save these values into the database .
This is the code I'm using :
foreach (Meal ml in mVals)
{
mID = ml.mealID;
MessageBox.Show(Convert.ToString(mID));
string oString2 = " INSERT into [dbo].[OrderMeal] (orderId,mealId,quantity) " + " VALUES ('" + orderId + "','" + mID + "','" + Convert.ToInt32(quant.Text) + "') ;";
SqlCommand oCmd2 = new SqlCommand(oString2, myConnection);
oCmd2.ExecuteNonQuery();
}
However, this only works for the last value in the list. The next loop iteration seems to be doing the same function, thereby saving the same record, giving an
error of violating the primary key constraint .
Is there some error in the way I am looping through the List?
What the structure of OrderMeal table?
Probably you have primary key in your table, and you need to vetify that you don't duplicate him.
try to enter the value in the list from the sql management.
verify that you don't have special characters in each item in the list( like comma and Apostrophe).
I think you can concatenate a set of insert statement and then ExcuteNonQuery for better performance.

Simple way to just store IEnumerable of some type into new SQL server database table (code first) C#

I'm looking for a simple way to store any data objects in SQL server without defining a table first.
Think about this pseudo code creating IEnumerable of anomyous type (LINQ):
var result = from item in items select new { item.First, item.Last, Age = 42 };
I'm looking for a simple solution, a function call like this:
// StoreResultInNewTable(database/context, tablename, result);
I'm aware of EF6 and code first, but I don't want to define an explicit type (class). And I don't need the other parts of entity framework like caching data or detailed tracking database layout. If table already exists and object cannot be stored in there, raise error. Otherwise (create table) and insert data.
Data inserts should not be too slow (SqlBulkCopy / BulkInsert).
edit: I really look for a solution where the result set is stored as plain database table in SQL server which means having a property of .NET type string stored as (n)varchar, decimal as money and so on. Column names in database should be 1:1 to property names. I'm flexible regarding details, but should be similar to EF6 mapping in effect (without explicitly defined types).
No key-value store, no storage of serialized objects, no NoSQL, no flat files.
edit 2: To make this more clear I give details about types in my example:
class Person
{
public string First {get; set;}
public string Last {get; set;}
}
IEnumerable<Person> items = ...
This means result is some IEnumerable<TypeWithoutName>. The compiler is the only one known the name TypeWithoutName but I can use it in a type-safe way, e.g. via LINQ. And I'm quite sure this type could be inspected by reflection.
As mentioned in comments: I'm looking for an ORM that takes the anonymous type in result and builds some create table statement with two nvarchar columns and one integer column (and corresponding inserts).
As I couldn't find an existing solution to my question, I hacked some code:
internal static void StoreEntitiesToDatabase<T>(this IEnumerable<T> elements, SqlConnection connection,
string tablename)
{
var sbc = new SqlBulkCopy(connection);
{
var table = new DataTable();
Type listType = typeof (T);
foreach (PropertyInfo propertyInfo in listType.GetProperties())
{
table.Columns.Add(propertyInfo.Name, propertyInfo.PropertyType);
sbc.ColumnMappings.Add(propertyInfo.Name, propertyInfo.Name);
}
foreach (T value in elements)
{
DataRow dr = table.NewRow();
foreach (PropertyInfo propertyInfo in listType.GetProperties())
{
dr[propertyInfo.Name] = propertyInfo.GetValue(value, null);
}
table.Rows.Add(dr);
}
string sqlsc = "CREATE TABLE " + tablename + "(";
for (int i = 0; i < table.Columns.Count; i++)
{
sqlsc += "[" + table.Columns[i].ColumnName + "] ";
int maxlen = table.Columns[i].MaxLength;
if (maxlen == -1) maxlen = 255;
if (table.Columns[i].DataType.ToString().Contains("System.Int32"))
sqlsc += " int ";
else if (table.Columns[i].DataType.ToString().Contains("System.Int64"))
sqlsc += " bigint ";
else if (table.Columns[i].DataType.ToString().Contains("System.DateTime"))
sqlsc += " datetime ";
else if (table.Columns[i].DataType.ToString().Contains("System.String"))
sqlsc += " nvarchar(" + maxlen + ") ";
else if (table.Columns[i].DataType.ToString().Contains("System.Double"))
sqlsc += " float ";
else if (table.Columns[i].DataType.ToString().Contains("System.Decimal"))
sqlsc += " money ";
else
throw new Exception("no mapping for " + table.Columns[i].DataType);
if (table.Columns[i].AutoIncrement)
sqlsc += " IDENTITY(" + table.Columns[i].AutoIncrementSeed.ToString() + "," +
table.Columns[i].AutoIncrementStep.ToString() + ") ";
if (!table.Columns[i].AllowDBNull)
sqlsc += " NOT NULL ";
sqlsc += ",";
}
sqlsc = sqlsc.Substring(0, sqlsc.Length - 1) + ")";
SqlCommand cmd = new SqlCommand(sqlsc, connection);
cmd.ExecuteNonQuery();
sbc.DestinationTableName = tablename;
sbc.WriteToServer(table);
}
}
Can be called like this:
using (var conn = new SqlConnection(connectionString))
{
conn.Open();
elems.StoreEntitiesToDatabase(conn, "myTable");
conn.Close();
}
The code above works just fine for my problem and supports elements of anonymous type.
Sidenode: I first tried to "trick" EF6 using this:
internal class DbQuickInsert<T> : DbContext where T : class
{
public DbSet<T> MyRecords { get; set; }
public DbQuickInsert(string databasename) : base(databasename)
{
}
}
internal static class HelperQuick
{
public static void InsertIntoDatabase<T>(this IEnumerable<T> records, string databasename) where T : class
{
var qi = new DbQuickInsert<T>(databasename);
qi.Configuration.AutoDetectChangesEnabled = false;
qi.BulkInsert(records);
qi.SaveChanges();
}
}
The latter code compiles but raises a runtime error because Entity Frameworkcannot handle anonymous types.
it sounds like you're hoping to use an RDBMs for exactly what it wasn't designed for. Look into a NoSQL solution like MongoDB for storing data like this.
Another potential option if you have to use SQL Server... I guess... would be to create an xml/json representation of your objects and store them in a table. That will make querying quite a challenge however.
A table such as the above described could be considered a key/value pair store, similar to the following:
CREATE TABLE keyValuePairs (
key varchar(200) not null primary key ,
value xml
)
or
CREATE TABLE keyValuePairs (
key varchar(200) not null primary key ,
value varchar(max)
)
In the first you could store your objects as xml, the second as json (or technically xml as well). You would need to query your table based on the appropriate key, or do some really fancy query work - assuming your value's "schema" can differ dependent on object type being stored.

Trickly null validation for SQL Query

"AND TT.[_TYPE] = CASE WHEN " + String.IsNullOrEmpty(lstTypeSearch.SelectedItem) ?
DBNull.Value} +
" IS NULL THEN TT.[_TYPE] ELSE " + lstTypeSearch.SelectedItem + " END ";
Above is a pseudo aspect of my query.
I need to do a validation of listbox item for null and then set as DBNull.Value, which is to be passed into CASE WHEN within SQL Query.
Any better way to achieve this? I am getting tons of String to Bool, Null to String conversion errors...
Further, is there anyway to pass DBNull.Value as a Parameter across data access layer?
EDIT: original query is in a Static class.
public static readonly string SqlGetItemsBy_Number_Capacity_Type =
"SELECT TT.[_NUMBER], " +
"TT.[CAPACITY], " +
"TT.[_TYPE], " +
"TS.[SESSIONE] " +
"FROM [ITEMS] AS TT, //some code
"WHERE //some code
"AND TT.[_TYPE] = CASE WHEN #Type IS NULL THEN TT.[_TYPE] ELSE #Type END";
If I run the same query in SQL Server, it works fine.
SELECT //some code
AND [_TYPE] = CASE WHEN NULL IS NULL THEN [_TYPE] ELSE #TYPE END
Finally: I decided to go with SQL Append and following to validate/set parameter.
string paramAppend;
var bld = lstTypeSearch.SelectedItem;
if (bld != null)
{
paramAppend = "AND TT.[_TYPE] = " + lstTypeSearch.SelectedItem.ToString();
}
else
paramAppend = "";
It looks like lstTypeSearch here represents a column name (hence parameterization: not an option), so the first thing I'd say is: make sure you white-list that. Rather than trying to do everything in one go, separate the two cases:
if(string.IsNullOrEmpty(lstTypeSearch.SelectedItem))
{
// nothing to check?
}
else
{
CheckValidColumn(lstTypeSearch.SelectedItem); // throws if white-list fails
sql.Append(" AND TT.[_TYPE] = [") // should probably add table alias
.Append(lstTypeSearch.SelectedItem)
.Append("]");
}
If I have misunderstood, and this isn't a column, then just parameterize:
if(string.IsNullOrEmpty(lstTypeSearch.SelectedItem))
{
// no restriction?
}
else
{
sql.Append(" AND TT.[_TYPE] = #type");
cmd.Parameters.AddWithValue("type", lstTypeSearch.SelectedItem);
}
// ...
cmd.CommandText = sql.ToString();
First, you should work with parameters, unless want to be exposed to potential sql injection threats.
Second, if you are building the sql dynamically in the code, a better approach would be to add the sql condition only if lstTypeSearch.SelectedItem is not an empty string or null. something like that:
sSql = "your sql query";
if(!String.IsNullOrEmpty(lstTypeSearch.SelectedItem)) {
sSql += "TT.[_TYPE] = '" + lstTypeSearch.SelectedItem + "'";
}
sSql += ";"
btw, what if the SelectedItem has a string that only contains white spaces? consider replacing the String.IsNullOrEmpty to String.IsNullOrWhiteSpace.
With the edit, you should be able to replace the last line with:
AND (#Type IS NULL OR TT.[_TYPE] = #Type)
far clearer, although frankly it doesn't make for great query cache plan usage or optimization; it would still, IMO, be better to just compose the correct SQL.
As for passing in the value:
object value = string.IsNullOrEmpty(lstTypeSearch.SelectedItem)
? (object)DBNull.Value : (object)lstTypeSearch.SelectedItem;
// ...
cmd.Parameters.AddWithValue("Type", value);
If null then feed that into the case when within SQL, so it will return all the data.
I'm interpreting this to mean that if there's no value specified then return all the rows, otherwise filter by that value.
I'm assuming lstTypeSearch.SelectedItem is your value and it's a string. If not, cast it or dig out the string value.
command.CommandText =
"SELECT * FROM TT WHERE #SelectedItem IS NULL OR TT.[_TYPE] = #SelectedItem";
var selectedItem = (string) lstTypeSearch.SelectedItem;
command.Parameters.AddWithValue("#SelectedItem",
String.IsNullOrEmpty(selectedItem) ? (object) DBNull.Value : selectedItem);
using (var dataReader = command.ExecuteReader())
{
...
}

Categories