Add object to collection failed for ColumnCollection of table [name] - c#

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"?

Related

Access Database with C#

I'm very new to C#, and I just learn coding as one of my hobbies.
I'm trying to develop a stand-alone Windows application using Visual Studio and an Access database.
I have some difficulties how to access the database.
Project is my table in the Access database and projectname and path are my columns in the project table.
I'm trying to read the folders Name in a certain path and writing the name and path of a folder into my table.
How do I compare and insert only the new folder created?
This is showing an error in my insert syntax!
string[] files = Directory.GetDirectories(#"C:\\SomePath\\Project_1\\Project_1\\Resources");
foreach (string file in files)
{
string name = new DirectoryInfo(file).Name;
String Root = Path.GetFullPath(file);
connection_2.Open();
OleDbCommand ListWrite = new OleDbCommand();
ListWrite.Connection = connection_2;
ListWrite.CommandText= "insert into Project (projectname,path) values ('" + name + "','" +Root+ "') where'"
+ name + "' != projectname ";
ListWrite.ExecuteNonQuery();
connection_2.Close();
}
An insert command does not allow a where statement the way you use it.
You will need to query the table for each of the directory names. If the result of the query is not empty, the specific directory name it is already present in the table. Otherwise, you can insert the new name with an insert.
I would suggest to write a new method for that check:
public bool DoesFolderAlreadyExistInTable(string folder_name, string path, OleDbConnection connection)
{
using (var ListWrite = new OleDbCommand("select count(*) as c from Project where name=#name and path=#path", connection)) {
ListWrite.Parameters.AddWithValue("#name", folder_name);
ListWrite.Parameters.AddWithValue("#path", path);
var result = ListWrite.ExecuteReader();
return result.Read() && result.GetInt32(0) > 0;
}
}
You just need to leave a space after where:
..where '...
However, the best solution for not having such issues as well as SQL injection is to use parameters:
ListWrite.CommandText= "insert into Project (projectname,path) values (#name, #path)";
ListWrite.Parameters.Add("#name",SqlDbType.NVarChar).Value = name;
ListWrite.Parameters.Add("#path",SqlDbType.NVarChar).Value = Root;
Also notice that the where clause does not have any sense in an insert statement. You have to handle it from code or putting a unique constraint on the projectname column.
A WHERE clause is not valid in an insert statement. I assume what you were attempting to do was prevent duplicate project names. One way you can do this in SQL Server is as shown, I've made the assumption it's valid in Access as well but this isn't always the case.
SQL
INSERT INTO Project (projectname, path)
SELECT DISTINCT 'yourpath', 'yourroot'
FROM Project
WHERE NOT EXISTS (SELECT projectname FROM Project WHERE projectname = 'yourpath')
C#
ListWrite.CommandText= "insert into Project (projectname,path) select distinct '" + name + "','" + Root + "') from Project where not exists (select projectname from Project where projectname = '" + name + "'";
As pointed out by LosWochos and apomene, you should also look into parameterized SQL.

How to preserve store procedure's formatting while creating it from one database to another using c# ado.net?

I am creating store procedures from one source database to another destination database using c# console application. For that i have list of store procedures from source database. I iterate through that list and get definition of that sp by this command
Select definition from sys.sql_modules where object_id = OBJECT_ID ('" + item.SPName + "')"
and whatever defintion i get for that sp i am executing that result in destination database by
var idrSPCreate = cmdSPCreate.ExecuteNonQuery();
by this method i can successfully create store procedures in destination database. but my problem is that i am losing all formatting/indentation in destination database. How to preserve sp's formatting/indentation? is there any way or my question is invalid?
Getting sp's definition's code is below :
var cmdTextSP = string.Format("Select definition from sys.sql_modules where object_id = OBJECT_ID ('" + item.SPName + "')");
cmd.CommandText = cmdTextSP;
var idrSP = cmd.ExecuteReader();
and executing that definition in destination database using below code :
while (idrSP.Read())
{
if (idrSP.HasRows)
{
var SPDefinition = idrSP.GetString(0);
connDest.Open();
cmdSPCreate = connDest.CreateCommand();
cmdSPCreate.CommandType = System.Data.CommandType.Text;
cmdSPCreate.CommandText = string.Format(SPDefinition);
var idrSPCreate = cmdSPCreate.ExecuteNonQuery();
connDest.Close();
}
}

Insert from One MS Access database to Another MS Access database

I have to take the data from MS Access DB to another.
This was insert statement used
cmd.CommandText = #"Insert Into [MS Access;PWD=pw;DATABASE=" + currentDBPath + #"].[Orders] Select * FROM [Orders] where OrderDate>=#" + from.ToShortDateString() + "# and OrderDate <=#" + to.ToShortDateString() + "# and IsCustomer=Yes ";
This statement works fine. But some one started to enter the data directly to target database and also in the source. This created duplicated records. Now I want to copy those orders from source which are not in the target DB's table.
Assuming Orders table has a primary key named IDOrers, you must bring both tables to one DB, so you can compare data.
Easy option: have in Sours DB a link to [Orders] on Destination DB, named OrdersDest. In that case you create on destination a query of missing orders, named MissingOrders :
SELECT Orders.* FROM Orders LEFT JOIN OrdersDest ON OrdersDest.IDOrders = Orders.IDOrders WHERE OrdersDest.IDOrders Is Null
Your Command will now look like this:
cmd.CommandText = #"Insert Into [MS Access;PWD=pw;DATABASE=" + currentDBPath + #"].[Orders] Select * FROM [MissingOrders] where OrderDate>=#" + from.ToShortDateString() + "# and OrderDate <=#" + to.ToShortDateString() + "# and IsCustomer=Yes ";
You could also pass the data through this linked table:
cmd.CommandText = #"Insert Into [OrdersDest] Select * FROM [MissingOrders] where OrderDate>=#" + from.ToShortDateString() + "# and OrderDate <=#" + to.ToShortDateString() + "# and IsCustomer=Yes ";
I didn't find any solution to what I was looking for in my question , So I decided to just delete the duplicated data in destination database.
I used the below statement to delete the data ,
Delete * from Orders where AutoOrderID in (SELECT Orders.AutoOrderID FROM Orders Inner JOIN OrdersSource ON OrdersSource .OrderId = Orders.OrderId and OrdersSource .OrderDate=Orders.OrderDate);

How to copy data from two different table and insert fetched records into another table

I am trying to insert data in my table which have 3 feild
(1) sendReqID type int(PK)
(2) RequestID type int (FK from table Request)
(3) DonorID type int (FK table Donor)
I know how to copy data from one table and insert into another table but I want to know how to insert data in table, when we have to extract values from two different tables. Following is my code which I am trying and unable to insert data into my table.
public void Req_SendID()
{
SqlConnection MySQL = new SqlConnection(ConfigurationManager.ConnectionStrings["RegistrationConnectionString"].ToString());
string copy = "insert into Send_Request(RequestID,DonorID) Select RequestID,DonorID from RequestID and DonorID from Donor where R_City='" + Session["BGroup"] + "' and" + "D_City='" + Session["city"] + "'";
SqlCommand com = new SqlCommand(copy, MySQL);
MySQL.Open();
com.ExecuteNonQuery();
MySQL.Close();
}
Please Help thanks in advance.
You need to join on the two tables...
insert into Send_Request(RequestID,DonorID)
Select r.RequestID, d.DonorID
from RequestID r inner join Donor d ON r.R_City = d.D_City
where R_City='" + Session["BGroup"] + "' and " + "D_City='" + Session["city"] + "'"
I'm assuming the relationship is as above. However, consider SQL Injection attacks and look to parametrize your query.
EDIT: Using Parameterized Query
var requestCity = Session["BGroup"].ToString();
var donorCity = Session["city"].ToString();
"insert into Send_Request(RequestID,DonorID)
Select r.RequestID, d.DonorID
from RequestID r inner join Donor d ON r.R_City = d.D_City
where R_City=#RequestCity and D_City=#DonorCity"
SqlCommand com = new SqlCommand(copy, MySQL);
com.Parameters.Add("#RequestCity", requestCity);
com.Parameters.Add("#DonorCity", donorCity);
....
However, I just saw your comment that there is no relationship between the tables, so the actual query above would be incorrect.

Alter table SqlCommand

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

Categories