TableMappings With TableName Instead of TableN - c#

I am not sure this is possible, but I just cant figured it out.
I have a SP in my DB as below:
CREATE PROCEDURE [dbo].[GetMyValue]
AS
SELECT Code, TypeDesc FROM IDType
SELECT Code, Race FROM Race
SELECT Code, Nation FROM Nationality
SELECT Code, [Language name] AS 'Language' FROM Languages
SELECT Code, Occupation FROM Occupation
SELECT Code, Country FROM Country
GO
What I am trying to do is map the table with the table name from DB like this:
Dim da As New SqlDataAdapter(cmd)
da.TableMappings.Add("IDType", "NRICType")
da.TableMappings.Add("Race", "Race")
da.TableMappings.Add("Nationality", "Nationality")
da.TableMappings.Add("Languages", "Languages")
da.TableMappings.Add("Occupation", "Occupation")
da.TableMappings.Add("Country", "Country")
da.Fill(ds)
instead of using TableN like this:
Dim da As New SqlDataAdapter(cmd)
da.TableMappings.Add("Table", "NRICType")
da.TableMappings.Add("Table1", "Race")
da.TableMappings.Add("Table2", "Nationality")
da.TableMappings.Add("Table3", "Languages")
da.TableMappings.Add("Table4", "Occupation")
da.TableMappings.Add("Table5", "Country")
da.Fill(ds)
Anyway, it doesn't seem working as when I try to access the value in the later part with Dim dt As DataTable = ds.Tables("NRICType"). The ds.Tables("NRICType") appears to be NULL. Everything work fine when I map it with TableN.
But the problem might happen in future is, what if the sequence of SELECT STATEMENT in SP changed? The mapping will definitely mess up. Code in C# would help too.

Chinz,
Here is a Hack that will give you what you are looking for...
In your Stored procedure add one additional field (TableName) to your selects
CREATE PROCEDURE [dbo].[GetMyValue]
AS
SELECT 'IDType' TableName, Code, TypeDesc FROM IDType
SELECT 'Race' TableName, Code, Race FROM Race
SELECT 'Nationality' TableName, Code, Nation FROM Nationality
SELECT 'Languages' TableName, Code, [Language name] AS 'Language' FROM Languages
SELECT 'Occupation' TableName, Code, Occupation FROM Occupation
SELECT 'Country' TableName, Code, Country FROM Country
GO
Now in your c# code after the da.Fill(ds)
da.Fill(ds);
for (int i = 0; i < ds.Tables.Count; i++)
{
if (i == 0)
da.TableMappings.Add("table", GetTableName(i, ds));
else
da.TableMappings.Add("table" + i.ToString(), GetTableName(i, ds));
}
GetTableName is a method to grab the first field from the DataTable
static string GetTableName(int tableIndex, DataSet ds)
{
if (ds.Tables[tableIndex].Rows.Count > 0)
return ds.Tables[tableIndex].Rows[0]["TableName"].ToString();
// If there aren't any rows I don't know the Table name and return table[index] as the name
return "table" + tableIndex.ToString();
}
Another way to do this is to make you first selection in the Stored Procedure the order and name of the Tables. Then in your c# code after the the da.Fill(ds) you can read the rows out of ds.tables[0] and use that for your table mappings.
I hope this helps.
If you don't want to deal with additional unwanted columns in your results, then consider the following
Your Stored Procedure will have an additional select which will be the first select and define the order of the tables being returned.
CREATE PROCEDURE [dbo].[GetMyValue]
AS
SELECT 'IDType' TableName, 1 as SortOrder
UNION
SELECT 'Race' TableName , 2 as SortOrder
UNION
SELECT 'Nationality' TableName , 3 as SortOrder
UNION
SELECT 'Languages' TableName ,4 as SortOrder
UNION
SELECT 'Occupation' TableName , 5 as SortOrder
UNION
SELECT 'Country' TableName, 6 as SortOrder
ORDER BY SortOrder
SELECT Code, TypeDesc FROM IDType
SELECT Code, Race FROM Race
SELECT Code, Nation FROM Nationality
SELECT Code, [Language name] AS 'Language' FROM Languages
SELECT Code, Occupation FROM Occupation
SELECT Code, Country FROM Country
GO
and in the c# code after the da.Fill(ds) do this
//string[] listOfTableNames;
listOfTableNames = GetTableNames(ds);
for (int i = 0; i < ds.Tables.Count; i++)
{
da.TableMappings.Add("table" + i.ToString(), listOfTableNames[i]);
}
and GetTableNames Method is defined as
static string[] GetTableNames( DataSet ds)
{
List<string> tablenames = new List<string>();
// The first Table contains the TABLE NAMES
tablenames.Add("TableNames");
if (ds.Tables[0].Rows.Count > 0)
foreach( DataRow row in ds.Tables[0].Rows)
{
tablenames.Add(row["TableName"].ToString());
}
return tablenames.ToArray();
}

As described in the documentation in MSDN thats the way it is supposed to be used.
http://msdn.microsoft.com/en-us/library/ms810286.aspx
If the Stored procedure is setup in that order, that order must be maintained in the future.
If you want to make this Dynimac you could verify the table schema and try to identify if you are looking at the correct table, but this will add a big cost in performance.
Dim da As New SqlDataAdapter(cmd)
da.TableMappings.Add("Table", "NRICType")
da.TableMappings.Add("Table1", "Race")
da.TableMappings.Add("Table2", "Nationality")
da.TableMappings.Add("Table3", "Languages")
da.TableMappings.Add("Table4", "Occupation")
da.TableMappings.Add("Table5", "Country")
da.Fill(ds)
Your second example is the correct use for this feature.

Related

Datatable rows.count == 0 gives 1 although there not found records in the table

I have a problem and I don't know why it's happening!
I am trying to find Max value in a column inside the database table, I use this code:
private void FrmCustomer_New_Load(object sender, EventArgs e)
{
int NewID;
DataTable _Dt = CusVar.GetCustomersIDs();
if (_Dt.Rows.Count == 0)
{
NewID = 1;
this.txt1.Text = NewID.ToString();
DataRow _Row = CusVar.GetCustomersIDs().Rows[0];
MessageBox.Show(Convert.ToString(_Dt.Rows[0]["MaxID"]));
}
}
the code is working but it gives 1 although there are no records in the table?
I use C# and Access database ACCDB.
I use this function in Cls_Customers:
public DataTable GetCustomersIDs()
{
DAL.DataAccessLayer DAL = new DAL.DataAccessLayer();
DataTable Dt = new DataTable();
Dt = DAL.DataSelect("Select Max(CustomerID) AS MaxID From TblCustomers", null);
DAL.CloseConn();
return Dt;
}
what is the problem, please?
This is your query:
Select Max(CustomerID) AS MaxID
From TblCustomers
It is an aggregation query. Aggregation queries with no group by always return one row -- regardless of whether any rows match.
The value returned in the single row is NULL for MaxId.
I am highly suspicious of what you want to do. If you want the maximum id -- and no rows if the table is empty -- then do:
select c.CustomerID
from TblCustomers c
order by c.CustomerID desc
fetch first 1 row only;
(This uses ANSI/ISO standard syntax so the exact logic might depend on your database.)
My suspicion is that you then want to use this id for an insert -- and that is a bad approach. Almost all databases support some sort of auto-incremented column (with syntax elements such as auto_increment, serial, or identity). That is the right way to assign a unique incrementing id to a column in a table.
The Sql query might be returning null and if there are no rows that match the criteria.
If the intention is to find the number of rows returned.Change the sql query to return the count instead of using aggregate function.
Try with this:
SELECT MAX(T1.CustomerID) AS MaxID From TblCustomers T1

Sort a DataTable by a specific column rather than the primary key

I am pretty new to C# and I am trying to link my Access database to the program and manipulate it and then later write it into a text file.
However, my data is currently sorted based on the ID (which is the primary key).
I would like to sort it based on Last Name and then do the manipulation because when I use "foreach(DataRow drr in dra)" the rows are retrieved in the order of the IDs.
[dra->Data Rows]
I would like to access the rows after they have been sorted but I am not sure of how to do it. The following is my code.
OleDbCommand myAccessCommand = new OleDbCommand(strAccessSelect, myAccessConn11);
OleDbDataAdapter myDataAdapter = new OleDbDataAdapter(myAccessCommand);
myAccessConn11.Open();
myDataAdapter.Fill(myDataSet, "Personal_Data");
myAccessConn11.Close();
DataTableCollection dta = myDataSet.Tables;
DataRowCollection dra = myDataSet.Tables["Personal_Data"].Rows;
foreach (DataRow drr in dra)
{
*Manipulation*
}
I tried using myDataSet.Tables["Personal_Data"].DefaultView.Sort = "LastName DESC"; but it didn't work.
Is there any other way in which I can sort the rows in the table before accessing them?
Thanks in Advance!
You can sort the rows in your "strAccessSelect" SQL query, e.g:
SELECT Id, FirstName, LastName from MyTable ORDER BY LastName ASC;

How to move a DataTable row to the first position of its DataTable

I want to get a specific row on an asp.net DataTable and move it to be the first one onto this DataTable base on a column column1 value. My Datatable dt1 is populated via a DB query and the value to search is via another query from another DB so I don't know the value to search at the dt1 select time.
// I use this variable to search into
// DataTable
string valueToSearch = "some value";
So I need to search the value some value into my DataTable in the column column1. and then move the entire row to the first position.
Thank you.
We have to clone the row data before:
DataRow[] dr = dtable.Select("column1 ='" + valueToSearch +"'");
DataRow newRow = dtable.NewRow();
// We "clone" the row
newRow.ItemArray = dr[0].ItemArray;
// We remove the old and insert the new
ds.Tables[0].Rows.Remove(dr[0]);
ds.Tables[0].Rows.InsertAt(newRow, 0);
You will have to test the performance on this, but one way to do this is in the query itself. Get the rows that you want at the top first, and combine that with the rest of the rows.
Since I know nothing of your database, here is a generic way to do this:
SELECT Column1, Column2, Column3
FROM MyTable
WHERE Column1 = 'some value'
UNION
SELECT Column1, Column2, Column3
FROM MyTable
WHERE Column1 <> 'some value'
If the column has only one record for the searched value than try this
DataRow[] dr = dtEmp.Select("column1 ='" + valueToSearch +"'");
myDataTable.Rows.InsertAt(dr[0], 0);

Prevent duplicate results in SQL

I have a combo box (comboBox1) in my application that lists catagories from my SQL database. It is pulling the data correctly at the moment. My only problem is that when the data is listed in the combo box, there are duplicate results. For example:
What I want it to list:
Example 1
Example 2
Example 3
What it actualy lists:
Example 1
Example 1
Example 1
Example 1
Example 1
Example 2
Example 2
Example 2
Example 3
Example 3
Example 3
Here is the code that I am using to list the data:
public void ListCat()
{
DataTable linkcat = new DataTable("linkcat");
using (SqlConnection sqlConn = new SqlConnection(#"Connection stuff;"))
{
using (SqlDataAdapter da = new SqlDataAdapter("SELECT name FROM list WHERE name <> 'NULL'", sqlConn))
{
da.Fill(linkcat);
}
}
foreach (DataRow da in linkcat.Rows)
{
comboBox1.Items.Add(da[0].ToString());
}
}
In short, my question would be how can I prevent duplicate data from being listed?
Use DISTINCT . It will eliminate the duplicate records.
Change your query to
SELECT DISTINCT name FROM list WHERE name <> 'NULL'
Assuming you may have stored the string value NULL inside your name column for some records.
If you have the real NULL in the name field, your query should be like this
SELECT DISTINCT name FROM list WHERE name is not NULL
Use DISTINCT
SELECT DISTINCT name FROM list WHERE name <> 'NULL'
Add a group by to the SELECT statement.
SELECT name FROM list WHERE name <> 'NULL' GROUP BY name

how to run query on dataset?

I have a DataSet named dsView that contains data. Here is the code i use to read the XML:
dsView = new DataSet();
dsView.ReadXml(#"\c:MyXml.xml");
The data has a table named MEN with fields Fname and Lname. How do I run a query on this dsView? (for example: select * from MEN where Fname = 'zz')
You cannot run complete SQL statements on a DataSet - but the DataTable inside your DataSet does have a method called Select(string) which selects an array of DataRow object that match a certain criteria.
Check out the MSDN docs on DataTable
You would probably have to do something like (untested):
DataTable tblMEN = dsView.Tables["MEN"];
DataRow[] results = tblMen.Select("Fname = 'zz'");
I don't think you can run a SQL query on a DataSet, since it doesn't have a query engine. But you could try LINQ to DataSet.
Also, if you are only interested in the data (and not the databinding properties of the DataSet), I suggest you use LINQ to XML to query the document.
dsView.Table[0].DefaultView.RowFilter = "Fname = 'zz'";
// now default view contains the filtered rows
//ds.Table[0].DefaultView
More about DefaultVeiw on msdn
AFAIK You can only run a Sql Like query on a DataTable with the Select method.
You would use this overload of DataTable.Select here to do something like this:
DataRow[] foundRows = dsView.Table[0].Select("Fname = `zz`");
dsView.Table[0] should point to the table of MEN and should have a column Fname
The expressions valid are the same as DataColumn expressions:
http://msdn.microsoft.com/en-us/library/system.data.datacolumn.expression.aspx
Here is an example that I used to make a menu.
Dim dstpage As DataSet
dstpage = businessService.GetData()
Dim userTable As DataTable
userTable = dstpage.Tables(0)
If userTable.Rows.Count > 0 Then
Dim results As DataRow()
results = userTable.Select("PAGE_GROUP_NAME='People'")
For i As Integer = 0 To results.Count - 1
FilePath = userTable.Rows(i)("FILE_PATH").ToString()
PageName = userTable.Rows(i)("PAGE_NAME").ToString()
Next
End If
// Create a table of five different people.
// ... Store their size and sex.
DataTable table = new DataTable("Players");
table.Columns.Add(new DataColumn("Size", typeof(int)));
table.Columns.Add(new DataColumn("Sex", typeof(char)));
table.Rows.Add(100, 'f');
table.Rows.Add(235, 'f');
table.Rows.Add(250, 'm');
table.Rows.Add(310, 'm');
table.Rows.Add(150, 'm');
// Search for people above a certain size.
// ... Require certain sex.
DataRow[] result = table.Select("Size >= 230 AND Sex = 'm'");
foreach (DataRow row in result)
{
Console.WriteLine("{0}, {1}", row[0], row[1]);
}
you can use this code.i hope it's help you.

Categories

Resources