.Net C# DataTables and DataSets, How to relate tables - c#

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);
}

Related

C# How to create a Dataset instance with relations between two tables

Well thats my problem. I'm trying to query a remote postgresql DB and then fill TWO RELATED instanced tables with the result, so i can fill a form that displays information for both tables. Doing this with a single table was simple, but now i'm unable to correctly define relationships. I'm getting the “Object reference not set to an instance of an object” error What im doing wrong?
Relation is "components/provider_id" to "provider/id" so i can fill provider fields automatically in the components forms (while doing a search query).
Heres my code:
OdbcDataAdapter sdata = new OdbcDataAdapter(//Query string whatever);
OdbcDataAdapter sdata2 = new OdbcDataAdapter(//Query string whatever);
DataSet ds = new DataSet(); //new dataset instance
DataTable dtbl = new DataTable(); //two new instanced tables
DataTable dtbl2 = new DataTable();
sdata.Fill(dtbl); //fill both tables with each query data
sdata2.Fill(dtbl2);
ds.Tables.Add(dtbl); //Add those tables to DataSet
ds.Tables.Add(dtbl2);
//So now im tring to create a relation between both tables
// im getting "“Object reference not set to an instance of an object”
DataRelation dr = new DataRelation("provcomp",
ds.Tables["dtbl"].Columns["id"],
ds.Tables["dtbl2"].Columns["id_prov_comp"]);
Also I suppose that after that i will need some advice on creating some keys for the columns.
Can I get a little help? Please keep in mind that im fairly new to programing in general and c# in particular.
You should add the relation to Relations collection of your DataSet:
DataSet ds = new DataSet(); //new dataset instance
DataTable dtbl = new DataTable("Your Parent TableName"); //two new instanced tables
DataTable dtbl2 = new DataTable("Your Child TableName");
sdata.Fill(dtbl); //fill both tables with each query data
sdata2.Fill(dtbl2);
ds.Tables.Add(dtbl); //Add those tables to DataSet
ds.Tables.Add(dtbl2);
ds.Relations.Add("Your Relation Name",dtbl.Columns["id"], dtbl2.Columns["id_prov_comp"]);
//or
//ds.Relations.Add(ds.Tables["dtbl"].Columns["id"], ds.Tables["dtbl2"].Columns["id_prov_comp"]);
ds.AcceptChanges();

how to add new datatable to dataset at first position

i have one dataset with 3 data tables again i have to add one more data table in same dataset at first position(Ex:mydataset.tables[0]th position) .can any one help me regarding this.
You will probably need to pull all the datatables out of the dataset into a list, get them in the right order, and then re-add them all to the dataset since you cannot insert to or modify the existing order:
var tables = new DataTable[4];
tables[0] = mynewtable;
tables[1] = mydataset.Tables[0];
tables[2] = mydataset.Tables[1];
tables[3] = mydataset.Tables[2];
mydataset.Tables.Clear();
mydataset.Tables.Add(Tables[0]);
mydataset.Tables.Add(Tables[1]);
mydataset.Tables.Add(Tables[2]);
mydataset.Tables.Add(Tables[3]);

How to go through two tables to create another table with common values

First Datatable is dt
var dt = new DataTable();
dt.Columns.Add("ID");
dt.Columns.Add("First Name");
dt.Rows.Add(1,"name1");
dt.Rows.Add(6,"name6");
dt.Rows.Add(4,"name4");
The second table is dt2
var dt2 = new DataTable();
dt2.Columns.Add("ID");
dt2.Columns.Add("First Name");
dt2.Columns.Add("Last Name");
dt2.Columns.Add("Birthday");
dt2.Rows.Add(1,"name1", "lastName1", 01.01.1991);
dt2.Rows.Add(2,"name2", "lastName2", 02.02.1992);
dt2.Rows.Add(3,"name3", "lastName3", 03.03.1993);
dt2.Rows.Add(4,"name4", "lastName4", 04.04.1994);
dt2.Rows.Add(5,"name5", "lastName5", 05.05.1995);
dt2.Rows.Add(6,"name6", "lastName6", 06.06.1996);
in the third DataTable dt3, I want to get those values ​​where ID is the same
result:
ID Name Birthdate
1 name1 01.01.1991
4 name4 04.04.1994
6 name6 06.06.1996
how to go through the DataTable's in c# ?
Unfortunately, there's no easy way, AFAIK, to join the 2 tables and get the third table automagically unless you are willing to write some code....
You can join them using Linq first:
var common = from c in dt.AsEnumerable()
join x in dt2.AsEnumerable() on c.Field<string>("ID") equals x.Field<string>("ID")
select new object[] { c["ID"],c["First Name"], x["Birthday"] };
And now you can create the destination table with the schema you want:
DataTable dt3 = new DataTable();
dt3.Columns.Add("ID");
dt3.Columns.Add("Name");
dt3.Columns.Add("Birthdate");
foreach (var item in common)
dt3.LoadDataRow(item.ToArray(),true);
Write an SQL Query or a Stored Procedure such that it joins the Two tables like you have depicted. Now use that Query for your DataTable with in .Net. You will get what you need.
Are you adding them to an actual database with a defined schema or just trying to do this in memory? If memory, I would add these to a DataSet which you can then use to filter the criteria becuase in the dataset, you can define their relationship.
You might be looking for adding Relationship between your tables. Check this link.
I guess you will need the DataTables to be in the same DataSet (you can add the DataTables into DataSet).

Why do I get empty results using generated code from DB?

I'm using SQL Server 2005. I have a table scores with 6 rows and columns - name, score and id.
I added the data source with VS and it generated a dataset called testDataSet.
So I tried the following code which gives me zero results:
testDataSet db = new testDataSet();
var result = from row in db.scores
select row.name;
Where is the problem?
The probem you are having is that you are querying an empty DataSet.
You first have to create a connection to your testDataSet and fill the tables contained in it with data from your database.
If you have created testDataSet with the automated tools VS provides then the tool will have also created the relevant TableDataAdapters (in their own namespace) to fill and update your DataSet.
Initialize the relevant TableDataAdapter and fetch the data from the database with the Fill(db) method.
you sould query dataTable like this:
DataTable products = ds.Tables["Product"];
var query = products.AsEnumerable().
Select(product => new
{
ProductName = product.Field<string>("Name"),
ProductNumber = product.Field<string>("ProductNumber"),
Price = product.Field<decimal>("ListPrice")
});
Try this code instead:
scoresTableAdapter adapter = new scoresTableAdapter();
var result = from row in adapter.GetData() select row.name;
Others are right that your problem is that you are not querying the data. When you generated the dataset, an adapter is also generated for you, that will help you to query the data as shown above.
The DataSet is just a structured container for the query results, it has no connection to the data source (database). In order to populate the DataSet with data you need to use a DataAdapter with a SelectCommand and call the Fill method.
var myConn = new SqlConnection ("..." );
var myAdapter = new SqlDataAdapter ( "SELECT * FROM TableName", myConn );
var myData = new testDataSet( );
myAdapter.Fill ( myData, "TableName" );

bind more than one dataGridView to MySQL database

I have MySQL database with four tables, and I've written form an example binding method. But this solution works well only with one table. If I bind more than one, dataGridViews will be filled with info, but Update and Delete commands work badly.
public void Bind(DataGridView dataGridView, string tableName)
{
string query = "SELECT * FROM " + tableName;
mySqlDataAdapter = new MySqlDataAdapter(query, conn);
mySqlCommandBuilder = new MySqlCommandBuilder(mySqlDataAdapter);
mySqlDataAdapter.UpdateCommand = mySqlCommandBuilder.GetUpdateCommand();
mySqlDataAdapter.DeleteCommand = mySqlCommandBuilder.GetDeleteCommand();
mySqlDataAdapter.InsertCommand = mySqlCommandBuilder.GetInsertCommand();
dataTable = new DataTable();
mySqlDataAdapter.Fill(dataTable);
bindingSource = new BindingSource();
bindingSource.DataSource = dataTable;
dataGridView.DataSource = bindingSource;
}
Should I use different mySqlDataAdapter or mySqlCommandBuilder for each new table? I've used different DataTable and BindingSource objects, but when I inserted new row in one table, I had an exception that I left empty field in other table. Any solutions or tips for this problem?
Thanks in advance!
Better late than never I guess...
I have an application that loads different tables into the same DataGridView using Visual Studio 2013. So far it is working!
1. DataTable
You certainly need to create a new one for each different table you want to load, otherwise you can not clear out the old data. You might think that
dataTable.Clear()
would do the trick but no, it leaves the old column headers behind so your new table is loaded to the right of all the old columns :-(. Although interestingly if your new table has a column with the same name as the old it merges them!
2. MySqlAdapter
I currently create a new one for each table, but at the very least your sql query is changing so you need to create a new SelectCommand:
MySqlCommand cmd = new MySqlCommand("SELECT * FROM `" + tableName + "`", conn);
sqlAdapter.SelectCommand = cmd;
I've tried this and it seems to work, but actually it is simpler to just create a new MySqlAdapter and performance really isn't an issue at this point!
3. SqlCommandBuilder
Yes you should create a new one because the update and delete commands will be different. I don't use a class variable but create one dynamically (i.e. as a local variable) when I need it.
4. BindingSource
I don't believe you need a new BindingSource, but I haven't used them very much so can't be certain.

Categories

Resources