Column [key] throws MissingPrimaryKeyException in dataTable - c#

var sdr = db.ExecuteReader("SELECT [key],translation FROM language WHERE lang=#lang");
DataTable someTable = new DataTable();
someTable.Load(sdr);
return ((string)(someTable.Rows.Find("[key] = CUSTOMDATEFORMAT").ItemArray[1]));
The last line now throws the error System.Data.MissingPrimaryKeyException: "The table has no primary key."
So I guess it finds the keyword "key" and now expects me to query on the primary key column, not the column named "key". How do I have to escape the column name?

If you want to use DataRowCollection.Find you have to specify the DataTable's PrimaryKey(s).
I would use Linq-To-DataTable:
DataRow row = someTable.AsEnumerable()
.FirstOrDefault(row => row.Field<string>("key") == "CUSTOMDATEFORMAT");
if(row != null)
return row.Field<string>(1); // or by name but with correct type
else
return "something else";
Then you can use all methods you want in the query.

The Find method is used to find a single rows by the primary key value. Use Select to find rows by arbitrary column values:
DataRow[] foundRows;
foundRows = someTable.Select("[key] = CUSTOMDATEFORMAT");
return foundRows[0].ItemArray[1]; // adding proper bounds checking, of course.

Find method is using the column that is specified in the DataTable object as primary key and return a row that contains the value it gets inside the primary key cell.
From MSDN:
Gets the row specified by the primary key value.
Since your table doesn't have a column that is specified as a primary key, you get this error.
If your key column is guaranteed to not contain duplicates, you can specify it as the primary key using the DataTable's PrimaryKey property.
If not, then use Linq's Select method instead of find:
return ((string)(someTable.Rows.Select("[key] = CUSTOMDATEFORMAT").ItemArray[1]));

Related

How to get value of second column, that is the same name with another column in dataTable by C#

I have a dataTable get from calling a stored procedure in SQL Server, it has 2 columns with the same name: NAME_PROJECT
Example: result from this query:
SELECT
NAME_PROJECT,
DATE,
...
NAME_PROJECT,
...
FROM
TABLE_A
This is my code in C#, it always get value of the first column:
dataTable.Rows[i].Field<string>("NAME_PROJECT")
Because some reason, I can not change KEY "NAME_PROJECT" from SQL to avoid the same name column.
How to get value of the second NAME_PROJECT column in this problem?
Thanks!
Field is overloaded to accept column index as well, you could use pass an index in this case.
dataTable.Rows[i].Field<string>(2);
Update:
Since you want to take second column when there are duplicate column names, I would suggest doing this.
var column = dataTable.Columns
.OfType<DataColumn>()
.LastOrDefault(x=> x.ColumnName == "columnname");
if(column != null)
{
dataTable.Rows[i].Field<string>(column);
}
You could alias one of the duplicate column names in your query so that the result set returned by the stored procedure doesn't have the duplicate column name problem
One solution is to use Index for selecting the column you need.
string Second_Name_Porject = dataTable.Rows[i].ItemArray[2];

UNIQUE constraint on DataTable

Can I have a clustered key on DataTable in C# ?
There's a requirement in my code to have constraints for possible combinations of 3 columns to be unique .....
What you need is really a unique constraint on your DataTable. Clustered keys are a SQL Server on-disk feature and not applicable to a DataTable.
Check out MSDN doc on DataTable constraints:
The UniqueConstraint object, which can be assigned either to a single column or to an array of columns in a DataTable, ensures that all data in the specified column or columns is unique per row. You can create a unique constraint for a column or array of columns by using the UniqueConstraint constructor.
So try something like this:
// this is your DataTable
DataTable custTable ;
// create a UniqueConstraint instance and set its columns that should make up
// that uniqueness constraint - in your case, that would be a set of *three*
// columns, obviously! Adapt to your needs!
UniqueConstraint custUnique =
new UniqueConstraint(new DataColumn[] { custTable.Columns["CustomerID"],
custTable.Columns["CompanyName"] });
// add unique constraint to the list of constraints for your DataTable
custTable.Constraints.Add(custUnique);
And that should do the trick for you!
To make your columns enforce a UNIQUE constraint you could use
DataTable dt = new DataTable();
dt.Columns.Add("UniqueColumn");
dt.Columns["UniqueColumn"].Unique = true;
Solution two
If you want some combination of the values in some columns to have unique value, you can try this.
DataTable dt = new DataTable();
dt.Columns.Add("UniqueColumn1");
dt.Columns.Add("UniqueColumn2");
dt.Columns.Add("UniqueColumn3");
dt.Columns.Add("NormalColumn");
string
value1 = string.Empty,
value2 = string.Empty,
value3 = string.Empty,
value4 = string.Empty;
//Logic to take values in string values variables goes here
DataRow[] founded = dt.Select("UniqueColumn1 = '"+ value1+
"' and UniqueColumn2 = '"+value2+
"' and UniqueColumn3 = '"+value3+"'");
if (founded.Length > 0)
// Message to say values already exist.
else
// Add a new row to your dt.
In this code you check the data present in DT to enforce uniqueness

get index of DataTable column with name

I have some code which sets the value of cells in a DataRow by column name i.e.
row["ColumnName"] = someValue;
I want to also set the value for this row in the column immediately to the right of the one found above. Clearly if I was getting the cell by index rather than by column name this would be easy. So is there a way of getting the column index from the column name thus allowing me to do:
row[index + 1] = someOtherValue;
i.e. do I need create some kind of dictionary of column index and column names when the table is initially created, or can I get the index from the column name later on without doing this?
You can use DataColumn.Ordinal to get the index of the column in the DataTable. So if you need the next column as mentioned use Column.Ordinal + 1:
row[row.Table.Columns["ColumnName"].Ordinal + 1] = someOtherValue;
Warning:
This code returns the next column, so the one after ColumnName, as requested in the question.
Try this:
int index = row.Table.Columns["ColumnName"].Ordinal;
You can simply use DataColumnCollection.IndexOf
So that you can get the index of the required column by name then use it with your row:
row[dt.Columns.IndexOf("ColumnName")] = columnValue;
I wrote an extension method of DataRow which gets me the object via the column name.
public static object Column(this DataRow source, string columnName)
{
var c = source.Table.Columns[columnName];
if (c != null)
{
return source.ItemArray[c.Ordinal];
}
throw new ObjectNotFoundException(string.Format("The column '{0}' was not found in this table", columnName));
}
And its called like this:
DataTable data = LoadDataTable();
foreach (DataRow row in data.Rows)
{
var obj = row.Column("YourColumnName");
Console.WriteLine(obj);
}

How to check if DataTable contains DataRow?

I have a non-typed dataset filled with data from user input (no database). There's no primary key column (my data had no need for primary key so far)! Is there any way to avoid "brute force" if i want to check if new row user is trying to insert already exists in my DataTable? How should i perform that check?
You can manually create unique constraints for your DataTable:
DataTable custTable = custDS.Tables["Customers"];
UniqueConstraint custUnique = new UniqueConstraint(new DataColumn[]
{custTable.Columns["CustomerID"],
custTable.Columns["CompanyName"]});
custDS.Tables["Customers"].Constraints.Add(custUnique);
For this example, you would get an exception (of type ConstraintException) if you tried to add a row to the table where the CustomerID and CompanyName were duplicates of another row with the same CustomerID and CompanyName.
I would just let the DataTable check these things for you internally - no point reinventing the wheel. As to how it does it (whether it is efficient or not), will have to be an exercise for you.
What you can do is use a DataView. Dataview allow you to use a where clause with the DataView's data.
Check it that way.
To check for any duplicates try
if (table.Rows.Contain(PriKeyTypeValue)) /*See if a Primary Key Value is in
the table already */
continue;
else
table.Row.Add(value1, value2, value3);
If you want to be able to insert duplicate rows but do not want to have an exception thrown set-up your primary key as a unique self-incrementing int then you can insert as many duplicates as you feel like without having to check to see if the table contains that value.you can set primary key value like the below....
DataTable table = new DataTable();
table.Columns.Add("Column", typeof(int));
DataColumn column = table.Columns["Column"];
column.Unique = true;
column.AutoIncrement = true;
column.AutoIncrementStep = 1; //change these to whatever works for you
column.AutoIncrementSeed = 1;
table.PrimaryKey = new DataColumn[] { column };
Much, much easier way:
datatable.Columns.Contais("ColumnName")

Custom DataSet.Table.FindBy method

I have a strongly-typed DataSet that was created using visual studio 2010's Configuration Wizard. I can find a DataRow easily as long as I know the primary key (see How to: Edit Rows in a DataTable).
The problem occurs when I don't know the PK. Is there a way to create a custom method that returns a DataRow if you have a combination of columns that could also be a composite primary key (unique constraint). Using the example from the link, I would like to do something like this:
NorthwindDataSet.CustomersRow customersRow = northwindDataSet1.Customers.FindByCustomerNameAndType("TestCustomerName", "TestCustomerType");
This assumes their Northwind DB Customers Table has two columns (name and type) that could also be a composite key. And the the FindBYCustomerNameAndType method would map to
SELECT *
FROM Customers
WHERE name = "TestCustomerName" AND type = "TestCustomerType"
string whereClause = "name = 'TestCustomerName' and type = 'TestCustomerType'";
DataRow[] x = northwindDataSet1.Customers.Select(whereClause);
if (x.Length > 0){
CustomersRow customersRow = x[0] as CustomersRow;
//other code here
}

Categories

Resources