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;
Related
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.
I am trying to change the datatype of one of the columns in a table using SqlCommand with parameters, but it doesn't work.
Here is my code:
Dictionary<string,string> dict = new Dictionary<string,string>();
dict.Add("#TableName",TableColumnArray[0].ToString( ));
dict.Add("#ColumnName",TableColumnArray[1].ToString( ));
DBSql.ExecSQLStatement( "ALTER TABLE #TableName ALTER COLUMN #ColumnName varchar(MAX)",dict,connectionStringName);
public static void ExecSQLStatement (string strsql,Dictionary<string,string> dict,string connectionStringName)
{
SqlConnection con = CreateSqlConnectionStr(connectionStringName);
SqlCommand cmd = new SqlCommand(strsql,con);
foreach(string dictKey in dict.Keys)
{
cmd.Parameters.Add(new SqlParameter(dictKey,dict[dictKey]));
}
con.Open( );
cmd.ExecuteNonQuery( );
con.Close( );
}
But the code keeps throwing an error:"Incorrect syntax near #TableName". I cannot find the solution to this problem. I could try to use stored procedures, but I really want to know why the code is not working. I usually use SqlCommand with parameters for select,insert statements, but it seems it doesnt work with alter statements?
because by default, tableName and column names CANNOT BE PARAMETERIZED. One way you can do to avoid sql injection is to create a User Define Function that check if the tableName is valid or not. Then concatenate the name on the string. eg,
Here's the UDF
private bool IsValidColumnNameOrTableName(string tablecolumnName)
{
// other codes
return returnValue;
}
You cannot use parameters in DDL statements. You should create the statement string dynamically:
DBSql.ExecSQLStatement(
"ALTER TABLE " + TableColumnArray[0] + " ALTER COLUMN " + TableColumnArray[1] + " varchar(MAX)",
dict,connectionStringName);
you need specify table name and column name exactly:
"ALTER TABLE " + TableColumnArray[0].ToString( ) + " ALTER COLUMN " + TableColumnArray[1].ToString( ) + "varchar(MAX)"
sql server does not allow syntax where table names and column names are variable values
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.
I am trying to delete entries by ID. I want to notify user that ID they try to delete doesn't exist. It doesn't create any problems, but I want to make everything clear.
How to do that? Do I have to use SQL string to do so?
I am using MS Access 2007 and this is how I delete item:
string SQL = "DELETE FROM PersonalData WHERE DataID = " + txtEntryID.Text;
private void DeleteData(string SQL)
{
// Creating an object allowing me connecting to the database.
// Using parameters in command will avoid attempts of SQL injection.
OleDbConnection objOleDbConnection = new OleDbConnection();
// Creating command object.
objOleDbConnection.ConnectionString =
"Provider=Microsoft.ACE.OLEDB.12.0;" +
"Data Source=" + filePath + ";" +
"Persist Security Info=False;" +
"Jet OLEDB:Database Password=" + pass + ";";
OleDbCommand objOleDbCommand = new OleDbCommand();
objOleDbCommand.CommandText = SQL;
// Assigning a connection string to the command.
objOleDbCommand.Connection = objOleDbConnection;
try
{
// Open database connection.
objOleDbConnection.Open();
objOleDbCommand.ExecuteNonQuery();
}
catch (Exception ex)
{
// Displaying any errors that
// might have occured.
MessageBox.Show("Error: " + ex.Message);
}
finally
{
// Close the database connection.
objOleDbConnection.Close();
}
// Refreshing state of main window.
mainWindow.DisplayFileContent(filePath);
MessageBox.Show("Data was successfully deleted.");
// Clearing text box field.
txtEntryID.Clear();
}
In VBA code, you could use the DCount() function.
You can also just delete the records with a SQL statement and inform the user after the fact; from the user's point of view there's no difference:
Dim id As Long
id = GetAnIdFromTheUser()
With CurrentDb
Do
.Execute "DELETE FROM [TableName] WHERE ID = " & id
If .RecordsAffected > 0 Then
Goto Done
End If
MsgBox "That ID doesn't exist; please try another."
id = GetAnIdFromTheUser()
Loop
Done:
.Close
End With
EDIT:
In ADO.NET you can follow the same approach by examining the return value of ExecuteNonQuery. For example, you could declare your function as bool TryDeleteData(string SQL) and do something like
...
if (objOleDbCommand.ExecuteNonQuery() == 0)
return false;
...
You could use the DCount function of VBA:
DCount("*", "SomeTable", "ID = 1")
If this is 0 then you know the record doesn't exist and can inform the user.
Your question isn't clear enough, so I'm guessing that what you'd like to do is execute the DELETE query and then return whether records were deleted or not. If that's what you want to do you could do it like this:
DECLARE #deletedID AS INT
SELECT #deletedID = id FROM your_table WHERE id = <the id supplied by user>
DELETE FROM your_table
WHERE your_table.id = <the id supplied by user>
RETURN #deletedID
If the requested ID does not exist this will return NULL
EDIT
Based on the clarification in your comments, the following query should work just fine:
SELECT COUNT(DataId) as Cnt
FROM PersonalData WHERE DataId = <user_specified_id>
This query will produce a single column, single row result set (i.e. a scalar-value). The value is going to be either 1 or 0 (assuming only one entry may have the same id). If the count is 0 the entry does not exist.
P.S.
The way you are executing the query you're opening yourself to SQL injection attacks. Basically, someone could give you the following DataID: 0 OR 1 = 1 and guess what's going to happen - all the PersonalData records will be deleted!
A much better approach would be to use prepared statements. Or at the very least, make absolute sure that you sanitize and validate the user input before concatenating it into the query text.
I have the following code:
IEnumerable<Table> tables = dbtables.ToList()
.Where(x => x.Name.StartsWith("PartStats"));
foreach (var tbl in tables)
{
Table JoinTable = new Table(db, "ProductMaterial");
JoinTable.Columns.Add(tbl.Columns[0]);
string tblName = tbl.Columns[0].Name;
string script =
#"ALTER TABLE [dbo].[ProductMaterial]
WITH CHECK ADD CONSTRAINT [FK_" + tbl.Name +
"] PRIMARY KEY([" + s;
string script2 = #"]) REFERENCES [dbo].[" + tbl.Name + "] ([" + tblName + "])" ;
string newscr = string.Concat(script, script2);
AddPrimaryKey(tbl, newscr);
This used to work, but now when I run it, I get this error:
"Add object to collection failed for ColumnCollection of table ProductMaterial".
AddPrimaryKey() just executes the script on the SQL Server, and is fine. The problem is in the preceding code to that method call.
The server is on, I am using local admin account for the SQL Server (my windows account is an admin for the SQL Server).
Thanks
Perhaps wrap the call in a check whether the column already exists on the table.
if (!JoinTable.Columns.Contains(tbl.Columns[0].Name)
{
JoinTable.Columns.Add(tbl.Columns[0]);
}
Could it be that you're trying to add multiple Tables named "ProductMaterial"?