I would like to ask for your help. The problem is that I am trying to relate two tables so I need to create primary keys on the tables each "id" columns but I am getting an error on this line
ds.Relations.Add(dr);
Error:
This constraint cannot be enabled as not all values have corresponding parent values.
(original error in Spanish = No se puede habilitar esta restricción ya que todos los valores no tienen los valores primarios correspondientes.)
What am I doing wrong?
OdbcDataAdapter sdata = new OdbcDataAdapter("SELECT * FROM componentes WHERE nombre_componente ILIKE '%" + buscar + "%'", conn);
OdbcDataAdapter sdata2 = new OdbcDataAdapter("SELECT * FROM proveedores WHERE nombre_empresa ILIKE '%" + buscar + "%'", conn);
DataSet ds = new DataSet();
DataTable dtbl = new DataTable("dtbl");
DataTable dtbl2 = new DataTable("dtbl2");
sdata.Fill(dtbl);
sdata2.Fill(dtbl2);
ds.Tables.Add(dtbl);
ds.Tables.Add(dtbl2);
dtbl.PrimaryKey = new DataColumn[] { dtbl.Columns["id"] };
dtbl2.PrimaryKey = new DataColumn[] { dtbl2.Columns["id"] };
DataRelation dr = new DataRelation("provcomp",
ds.Tables["dtbl"].Columns["id_prov_comp"],
ds.Tables["dtbl2"].Columns["id"]);
ds.Relations.Add(dr);
ds.AcceptChanges();
Thanks in advance.
The primary keys are ok - you already successfully created them with the following lines:
dtbl.PrimaryKey = new DataColumn[] { dtbl.Columns["id"] };
dtbl2.PrimaryKey = new DataColumn[] { dtbl2.Columns["id"] };
The problem is (as indicated by the exception) in the DataRelation. DataRelation is the equivalent of the database FK (foreign key). The signature of the used constructor looks like this:
public DataRelation(
string relationName,
DataColumn parentColumn,
DataColumn childColumn
)
I think what you did wrong is specifying the wrong columns - parentColumn should point to the table being referenced while childColumn - the table referencing it.
Simple change it to:
DataRelation dr = new DataRelation("provcomp",
ds.Tables["dtbl2"].Columns["id"],
ds.Tables["dtbl"].Columns["id_prov_comp"]);
and if they are really related correctly, the problem should be solved.
Edit: In case the parent table does not contain all the keys from the child table, you might consider using this constructor overload and pass createConstraints = false, which will prevent the exception, but note that some child records will not to find their parent record.
DataRelation dr = new DataRelation("provcomp",
ds.Tables["dtbl2"].Columns["id"],
ds.Tables["dtbl"].Columns["id_prov_comp"],
false);
The problem here is your data. You're adding a primary key to each table and then attempting to link them with a foreign key.
However, from the error message you are receiving, it sounds like you are attempting to link dtbl to an id from dtbl2 which does not exist.
I would try to do a SQL query to find out where your problem records lie and then choose to either add a "parent", change the parent or delete the record.
SELECT * FROM componentes WHERE id_prov_comp NOT IN (SELECT ID FROM proveedores )
The parent column (that is primary key) must come before the child column (that is foreign key). Try this:
DataRelation dr = new DataRelation("provcomp",
ds.Tables["dtbl2"].Columns["id"],
ds.Tables["dtbl"].Columns["id_prov_comp"]);
Related
I want to update set of rows using ODP.net.
I want to get list of employees based on increasing asscending order of PRIORITY and update PRIORITY column with value 1 and increment by 1.
I tried below approach and it gives error "Dynamic SQL generation failed. No key information found"
StrQuery = "SELECT * FROM EMPLOYEE WHERE DEPT ='" + dept + "' ORDER BY PRIORITY";
DataTable dt = new DataTable();
OracleDataAdapter da = new OracleDataAdapter();
da.SelectCommand = new OracleCommand(StrQuery, ora);
OracleCommandBuilder cb = new OracleCommandBuilder(da);
da.Fill(dt);
intNpriority = 1;
foreach (DataRow row in dt.Rows)
{
row["PRIORITY"] = intNpriority;
intNpriority = intNpriority + 1;
}
da.UpdateCommand = cb.GetUpdateCommand();
da.Update(dt);
The table has no primary key and i cannot add one now. Can i add custom update query and how? Is there anyalternative way to acheive same?
table strucure:
column name | (data type)
Employee_name | (varchar2)
dept | (varchar2)
PRIORITY | (NUMBER)
I've spent two days to find some way to workaround.
Lucky that I could get it done.
The idea is to add a dump primary key in the DataTable, this new dump column does not affect the real database table.
Here's my code sample
Dim currentRow = m_DataTable.Rows(m_RowPosition)
Dim tmpRows() As DataRow = {currentRow}
Dim cmdBuilder As OracleCommandBuilder = New OracleCommandBuilder(m_Adapter)
**If m_DataTable.PrimaryKey.Count = 0 Then
m_DataTable.Columns.Add(New DataColumn("_ID_", System.Type.GetType("System.String")))
m_DataTable.Columns("_ID_").Unique = True
End If**
m_Adapter.Update(tmpRows)
Note: The currentRow is the row is being edited .
Please consider carefully to apply this tip because it might update all data of table.
It's suitable for case your table has only one row ( some kind of configuration data )
Scenario:
Excel file is read and displayed in datagrid.
Values in sql server must be updated if excel values are different.
Table in Sql server don't have primary key
After all these steps, when I am about to update the table, it throws the error saying "Update requires a valid UpdateCommand when passed DataRow collection with modified rows."
There is no primary key. So I need to use update command. BUt how and what would be in update command? importdata is dictionary where data from excel are stored. PLz help!!! What should I do now? I have No idea....
foreach (DataColumn column in ds.Tables[0].Columns)
{
string fieldName = column.ColumnName;
string fieldNameValueE = string.Empty;
if (importdata.ContainsKey(fieldName))
{
fieldNameValueE = importdata[fieldName];
foreach (DataRow dr in ds.Tables[0].Rows)
{
string fieldNameValueD = dr[fieldName].ToString();
if (fieldNameValueD != fieldNameValueE)
{
dr[fieldName] = fieldNameValueE;
}
}
}
}
da.Update(ds);
connection.Close();
So, let's say we were dealing with a table that had a primary key:
CREATE TABLE TableA
{
FieldA INT PRIMARY KEY IDENTITY(1, 1),
FieldB VARCHAR(256) NULL,
FieldC VARCHAR(256) NOT NULL,
}
If you were to use the SqlCommandBuilder (which you cannot because you don't have a primary key), it would build a statement a bit like this:
UPDATE TableA
SET FieldB = #p1,
FieldC = #p2
WHERE (FieldA = #p3 AND
((FieldB IS NULL AND #p4 IS NULL) OR (FieldB = #p5)) AND
FieldC = #p6)
So, you're going to need to build an UPDATE statement that's very similar to do it the way they do. But one thing you need to remember is it's not just the statement, you also have to add all of the parameters to the command that you build - and that's going to become pretty cumbersome.
So, I have two recommendations for you:
Make a primary key on the table.
Issue an ExecuteNonQuery in every iteration of the loop.
The second recommendation would look like this:
foreach (DataColumn column in ds.Tables[0].Columns)
{
string fieldName = column.ColumnName;
string fieldNameValueE = string.Empty;
if (importdata.ContainsKey(fieldName))
{
fieldNameValueE = importdata[fieldName];
foreach (DataRow dr in ds.Tables[0].Rows)
{
string fieldNameValueD = dr[fieldName].ToString();
if (fieldNameValueD != fieldNameValueE)
{
dr[fieldName] = fieldNameValueE;
}
var cmd = new SqlCommand(string.Format(
"UPDATE importdata SET {0} = {1} WHERE fielda = #fielda AND fieldb = #fieldb ...",
fieldName, fieldNameValueE), connectionObject);
cmd.Parameters.AddWithValue(#fielda, dr["fielda", DataRowVersion.Original]);
cmd.Parameters.AddWithValue(#fieldb, dr["fieldb", DataRowVersion.Original]);
cmd.ExecuteNonQuery();
}
}
}
Use SqlCommandBuilder.
After setting up your DataAdapter, initialize a command builder.
Then use the SqlCommandBuilder update feature.
SqlCommandBuilder cb = new SqlCommandBuilder(da);
//Do your other work updating the data
cb.DataAdapter.Update(ds);
That should do the trick!
Edit:
As BigM pointed out, your table needs to have a primary key for the SqlCommandBuilder to work. If however, you can't modify the actual SQL table and mark one of the fields as a Primary Key and you also know that one of the fields is unique, you can add a Primary Key to your DataSet table like this:
DataColumn[] pk1 = new DataColumn[1];
pk1[0] = ds.Tables["TableName"].Columns[0];
ds.Tables["TableName"].PrimaryKey = pk1;
This gives your "in memory" table a primary key so that the SqlCommandBuilder can do its work.
Warning:
You must be sure that the values in the column you mark as primary key are actually unique.
I wrote a simple test to check my dataAdapter code. I connect to the SQL Server database, fill a datatable, change a value in a row, and call da.Update(table) to send the changes back to SQL Server. The table has a primary key. Not at all sure why this isn't working...(see code)
connectionToSQL = new SqlConnection(SQLConnString);
connectionToSQL.Open();
var wktbl = new DataTable();
var cmd = new SqlCommand("SELECT * FROM TAGS$",connectionToSQL);
var da = new SqlDataAdapter(cmd);
var b = new SqlCommandBuilder(da);
da.Fill(wktbl);
wktbl.Rows[3][2] = "5";
wktbl.AcceptChanges();
da.Update(wktbl);
Just skip the call to AcceptChanges and the code should work fine. It marks all rows as unmodified so there's nothing left to do for your Update call.
Okay, I would like to expand my question to my original effort...I select * from an Excel spreadsheet into dt. I want to take those values and update the SQL table. (the SQL table exists because of a manual import to SQL from the original Excel spreadsheet, has a primary key set, user updates the excel sheet, I need to update the SQL values.) I am setting the RowState to modified in an effort to invoke the Update.
connectionToSQL = new SqlConnection(SQLConnString);
connectionToSQL.Open();
var cmd = new SqlCommand("SELECT * FROM TAGS$",connectionToSQL);
var da = new SqlDataAdapter(cmd);
var b = new SqlCommandBuilder(da);
//dt.Rows[3][2] = "20";
foreach (DataRow r in dt.Rows)
{
r.SetModified();
}
da.Update(dt);
I've got an assignment which requires me to update the northwind database,
I've done everything like the tutorials say as follows
I fill The DataTable Using The DataAdapter.Fill(table).
I build the Delete,Insert,Update Commands using CommangBuilder
SqlDataAdapter adapter = new SqlDataAdapter(selectStr, conn);
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
adapter.DeleteCommand = builder.GetDeleteCommand(true);
adapter.UpdateCommand = builder.GetUpdateCommand(true);
adapter.InsertCommand = builder.GetInsertCommand(true);
adapter.Fill(employees_table);
I also set a primary key for the table:
DataColumn[] employees_keys = new DataColumn[2];
employees_keys[0] = employees.Columns["EmployeeID"];
employees_table.PrimaryKey = employees_keys;
Now I've attempted to delete and add a row:
// accepts an employee object and creates a new new row with the appropriate values for
// an employee table row
DataRow row = ConvertEmployeeToRow(employeeToAdd);
employee_table.Rows.Add(row);`
and deleting a row:
DataRow row = employees.Rows.Find(employeeToDismiss.ID);
employees.Rows.Remove(row);
I should also point out that I've attempted to use row.SetAdded() and row.Delete()
Anyway, at the end when I try to update the database
int k = employees_adapter.Update(employees_table);
on added rows sometimes k get valued, on remove never, and in either case nothing really gets updated at all in the database itself.
Any insight of what I'm doing wrong?
Make sure you're calling employee_table.AcceptChanges() after the call to Update() to save the changes to the database.
Check if the CommandBuilder really makes an Update command for you, like this:
MessageBox.Show(adapter.UpdateCommand.CommandText);
If the primary key info is missing it won't build the update command at all!
I am little confuse here your SqlDataAdapter name is adapter and you are doing updation in employees_adapter.The steps are so simple to work with SqlDataAdapter just follow theses
Step No 1:
SqlDataAdapter adapter = new SqlDataAdapter(selectStr, conn);
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
DataTable employees_table= new DataTable ();
adapter.Fill(employees_table);
Step No 2:
After you got the data in dataset start manipulation on it..
To insert :
DataRow MyRow = employees_table.NewRow();
//Now Fill data in MyRow
employees_table.Tables[0].Rows.Add(MyRow);
employees_table.AcceptChanges();
adapter.Update(employees_table);
To Delete :
/get only the rows you want
DataRow[] result = employees_table.Select("ID ="+id); //id will be provided by you
//Now do here data updation
employees_table.AcceptChanges()
adapter.Update(employees_table);
Like wise you can apply updation..But after doing any changes must call
table.AcceptChanges() and then'adapter.Update(employees_table)'
How do you take a couple of data tables and put them in a dataset and relate (that doesn't even sound like correct English) them?
I know how to create datatables.
Here is an example from one of my classes
// create the relationship between Booking and Booking_MNI
DataRelation relBookingMNI;
relBookingMNI = new DataRelation("BookingToBookingMNI",dsBooking.Tables["Booking"].Columns["Record_Id"],dsBooking.Tables["Booking_MNI"].Columns["booking_record_id"]);
dsBooking.Relations.Add(relBookingMNI);
dsBooking is my main dataset that contains 2 tables Booking and Booking_MNI
Where the Record_Id is the primary key and booking_record_id is the foreign key
I changed the code below to match my first example. But I think this is what you are looking for. In our production code this will produce the plus "+" symbol to the left of the row which would allow you to drill into the related table. Again I took production code and made it look like the first example so I don't know if it will compile but it should get you going in the right direction.
DataTable dtBooking = ds.Tables[0];
DataTable dtBooking_MNI = ds.Tables[1];
dtBooking.PrimaryKey = new DataColumn[] {dtBooking.Columns["Record_Id"]};
dtBooking_MNI.PrimaryKey = new DataColumn[] {dtBooking_MNI.Columns["booking_Record_Id"]};
/* Setup DataRelation between the DataTables */
DataColumn[] dcBookingColsArray = new DataColumn[1] {dtBooking.Columns["Record_Id"]};
DataColumn[] dcBookingMNIColsArray = new DataColumn[1] {dtBooking_MNI.Columns["booking_record_Id"]};
DataRelation relBooking_To_MNI = new DataRelation("Booking_To_MNI",dcBookingColsArray,dcBookingMNIColsArray);
ds.Relations.Add(relBooking_To_MNI_Units);
// grid where you want to display the relationship
grdBooking.DataSource = ds;
Look at the DataRelation class. It is what is used in a DataSet to relate two DataTables together.
Let's say you've got your DataTables named "orders" and "orderDetails". You want to create a relationship between them by their OrderNumber columns. We'll assume that orders is the parent and orderDetails is the child. We want to loop through the orders and then print each one's related sub-totals.
DataSet orderData = new DataSet("OrderData");
orderData.Tables.Add(orders);
orderData.Tables.Add(orderDetails);
orderData.Relations.Add("Order_OrderDetails", orders.Columns["OrderNumber"], orderDetails.Columns["OrderNumber"]);
Now, when you want to use that relationship somewhere else in your code:
DataRelation orderRelation = orderData.Relations["Order_OrderDetails"];
foreach (DataRow order in orders.Rows)
{
Console.WriteLine("Subtotals for Order {0}:", order["OrderNumber"]);
foreach (DataRow orderDetail in order.GetChildRows(orderRelation))
{
Console.WriteLine("Order Line {0}: {1}", orderDetail["OrderLineNumber"], string.Format("{0:C}", orderDetail["Price"]));
}
}
try this here is two table 1. categories & 2. Products
string query = "SELECT * FROM Categories; SELECT * FROM Products";
SqlConnection con = new SqlConnection();
SqlDataAdapter da = new SqlDataAdapter(query,con);
DataSet ds = new DataSet();
da.Fill(ds, "CategoriesAndProducts"); //CategoriesAndProducts dataset
string s = ds.Tables[0].Rows[0]["Name"].ToString();
string s1 = ds.Tables[1].Rows[0]["Name"].ToString();
Console.WriteLine(s); //from categories [0][0] like Electronic
Console.WriteLine(s1); //from Products [0][0] like LG
Have you looked into LINQ?
http://msdn.microsoft.com/en-us/netframework/aa904594.aspx
Perhaps you're looking for an orm solution like Entity Framework, NHibernate or Linq to SQL?
Appologies if I've misunderstood the question.
If you use Visual Studio 2005 or later try the following:
Right-click your project and select "Add/NewItem...", then choose DataSet from the wizard, which will create you some xsd and open the dataset designer.
Now you can create multiple tables, add columns to each table and draw relations (foreign key, with/without cascading...) between those tables.
in the autogenerated [YourNewDataSet}.Designer.cs-file, you will find the source code for these relations.
Something like this:
this.relationFK_DataTable2_DataTable1 = new global::System.Data.DataRelation("FK_DataTable2_DataTable1", new global::System.Data.DataColumn[] {
this.tableDataTable2.asdfasColumn}, new global::System.Data.DataColumn[] {
this.tableDataTable1.asdfaColumn}, false);
As always you can strip quite some portion of this code, if you code by hand instead of using the designer.
private void CreateRelation()
{
// Get the DataColumn objects from two DataTable objects
// in a DataSet. Code to get the DataSet not shown here.
DataColumn parentColumn =
DataSet1.Tables["Customers"].Columns["CustID"];
DataColumn childColumn =
DataSet1.Tables["Orders"].Columns["CustID"];
// Create DataRelation.
DataRelation relCustOrder;
relCustOrder = new DataRelation("CustomersOrders",
parentColumn, childColumn);
// Add the relation to the DataSet.
DataSet1.Relations.Add(relCustOrder);
}