How do I check if specified column exists in MS Access database? - c#

I need my program check if specified column exists in MS Access 2000 database, and if it doesn't - add it. I use .NET Framework 2.0
I tried to use oleDbConnection.GetSchema() method, but couldn't find column names in metadata (i'm really not a pro, huh) and any specification on msdn.
I would appreciate any help.
Thanks for answers.
Here is solution i used in my code:
bool flag = false; string[] restrictions = new string[] { null, null, mytable };
DataTable dtColumns = oleDbConnection1.GetOleDbSchemaTable(System.Data.OleDb.OleDbSchemaGuid.Columns, restrictions);
foreach (DataRow row in dtColumns.Rows)
{
if (mycolumnname==(string)row["COLUMN_NAME"]) flag = true;
}

This is code that is part of a o/r-mapper of mine. You cannot use it as is beacuse it depends on other classes, but I hope you get the picture.
Define restrictions like this
string[] restrictions = new string[] { null, null, tableName };
This retrieves the columns from a table
private void RetrieveColumnInfo(OleDbConnection cnn, TableSchema tableSchema,
string[] restrictions, Func<string, string> prepareColumnNameForMapping)
{
using (DataTable dtColumns =
cnn.GetOleDbSchemaTable(OleDbSchemaGuid.Columns, restrictions)) {
string AutoNumberColumn = RetrieveAutoNumberColumn(cnn, tableSchema);
foreach (DataRow row in dtColumns.Rows) {
var col = new TableColumn();
col.ColumnName = (string)row["COLUMN_NAME"];
try {
col.ColumnNameForMapping =
prepareColumnNameForMapping(col.ColumnName);
} catch (Exception ex) {
throw new UnimatrixExecutionException(
"Error in delegate 'prepareColumnNameForMapping'", ex);
}
col.ColumnAllowsDBNull = (bool)row["IS_NULLABLE"];
col.ColumnIsIdentity = col.ColumnName == AutoNumberColumn;
DbColumnFlags flags = (DbColumnFlags)(long)row["COLUMN_FLAGS"];
col.ColumnIsReadOnly =
col.ColumnIsIdentity ||
(flags & (DbColumnFlags.Write | DbColumnFlags.WriteUnknown)) ==
DbColumnFlags.None;
if (row["CHARACTER_MAXIMUM_LENGTH"] != DBNull.Value) {
col.ColumnMaxLength = (int)(long)row["CHARACTER_MAXIMUM_LENGTH"];
}
col.ColumnDbType = GetColumnDbType((int)row["DATA_TYPE"]);
col.ColumnOrdinalPosition = (int)(long)row["ORDINAL_POSITION"];
GetColumnDefaultValue(row, col);
tableSchema.ColumnSchema.Add(col);
}
}
}

Related

How to return names of all columns?

Searching, I found the PRAGMA as a possible solution for my problem, but it only returns the index of each column. There's any other method to return all columns names?
I thought using a For to go through my column indexes returning their names would works fine, but I dont exactly know how the syntax of this would be, either the stop condition.
void FillColumnList()
{
try
{
string check = "SELECT * FROM PRAGMA table_info(Produtos)";
sqlCon.Open();
SQLiteCommand tst2 = new SQLiteCommand(check, sqlCon);
SQLiteDataReader rdr2 = tst2.ExecuteReader();
if (rdr2.HasRows)
{
while (rdr2.Read())
{
string columns = rdr2[0].ToString();
Columns.Add(columns);
}
sqlCon.Close();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
}
This code should return and fill the Global variable list Columns with the name of each column of "Produtos" table. Instead of it, my DataReader 'rdr2' return false in the HasRows, even when there's columns and Datas in my table "Produtos"
You can use the connection's GetSchema method to retrieve the column information. I'm using the following code to insert information my own class TableColumn not shown here:
string[] restrictions = new string[] { null, null, tableName };
using (DataTable columns = conn.GetSchema("Columns", restrictions)) {
int nameIndex = columns.Columns.IndexOf("COLUMN_NAME");
int ordinalPosIndex = columns.Columns.IndexOf("ORDINAL_POSITION");
int isNullableIndex = columns.Columns.IndexOf("IS_NULLABLE");
int maxLengthIndex = columns.Columns.IndexOf("CHARACTER_MAXIMUM_LENGTH");
int dataTypeIndex = columns.Columns.IndexOf("DATA_TYPE");
int isPrimaryKeyIndex = columns.Columns.IndexOf("PRIMARY_KEY");
int hasDefaultIndex = columns.Columns.IndexOf("COLUMN_HASDEFAULT");
int defaultValueIndex = columns.Columns.IndexOf("COLUMN_DEFAULT");
foreach (DataRow row in columns.Rows) {
var col = new TableColumn {
ColumnName = (string)row[nameIndex]
};
try {
col.ColumnNameForMapping = prepareColumnNameForMapping(col.ColumnName);
} catch (Exception ex) {
throw new UnimatrixExecutionException("Error in delegate 'prepareColumnNameForMapping'", ex);
}
col.ColumnOrdinalPosition = (int)row[ordinalPosIndex];
col.ColumnAllowsDBNull = (bool)row[isNullableIndex];
col.ColumnMaxLength = (int)row[maxLengthIndex];
string explicitDataType = ((string)row[dataTypeIndex]).ToLowerInvariant();
col.ColumnDbType = GetColumnDbType(explicitDataType);
col.ColumnIsPrimaryKey = (bool)row[isPrimaryKeyIndex];
col.ColumnIsIdentity = explicitDataType == "integer" && col.ColumnIsPrimaryKey;
col.ColumnIsReadOnly = col.ColumnIsIdentity;
if ((bool)row[hasDefaultIndex]) {
col.ColumnDefaultValue = GetDefaultValue(col.ColumnDbType, (string)row[defaultValueIndex]);
if (col.ColumnDefaultValue == null) { // Default value could not be determined. Probably expression.
col.AutoAction = ColumnAction.RetrieveAfterInsert;
}
}
tableSchema.ColumnSchema.Add(col);
}
}
You can simplify this code considerably if you only need the column names.

Cannot implicitly convert DateTime to Timespan

Sql Server has the variable TEST_TIME data type as Time(7)
I created the tables in C# and it automatically assigned the Timespan datatype.
Now, i'm trying to upload csv file data to the SQL database and it is giving me an error " Cannot implicitly convert DateTime to Timespan". What would be the best way to fix this?
The user first selects the CSV file:
private void button8_Click(object sender, EventArgs e)
{
try
{
using (OpenFileDialog openfiledialog1 = new OpenFileDialog()
{Filter = "Excel Workbook 97-2003|*.xls|Excel Workbook|*.xlsx|Excel Workbook|*.xlsm|Excel Workbook|*.csv|Excel Workbook|*.txt", ValidateNames = true })
{
--After some IFs--
else if (openfiledialog1.FilterIndex == 4)
{
DataTable oDataTable = null;
int RowCount = 0;
string[] ColumnNames = null;
string[] oStreamDataValues = null;
//using while loop read the stream data till end
while (!oStreamReader.EndOfStream)
{
String oStreamRowData = oStreamReader.ReadLine().Trim();
if (oStreamRowData.Length > 0)
{
oStreamDataValues = oStreamRowData.Split(',');
//Bcoz the first row contains column names, we will populate
//the column name by
//reading the first row and RowCount-0 will be true only once
if (RowCount == 0)
{
RowCount = 1;
ColumnNames = oStreamRowData.Split(',');
oDataTable = new DataTable();
//using foreach looping through all the column names
foreach (string csvcolumn in ColumnNames)
{
DataColumn oDataColumn = new DataColumn(csvcolumn.ToUpper(), typeof(string));
//setting the default value of empty.string to newly created column
oDataColumn.DefaultValue = string.Empty;
//adding the newly created column to the table
oDataTable.Columns.Add(oDataColumn);
}
}
else
{
//creates a new DataRow with the same schema as of the oDataTable
DataRow oDataRow = oDataTable.NewRow();
//using foreach looping through all the column names
for (int i = 0; i < ColumnNames.Length; i++)
{
oDataRow[ColumnNames[i]] = oStreamDataValues[i] == null ? string.Empty : oStreamDataValues[i].ToString();
}
//adding the newly created row with data to the oDataTable
oDataTable.Rows.Add(oDataRow);
}
}
}
result.Tables.Add(oDataTable);
//close the oStreamReader object
oStreamReader.Close();
//release all the resources used by the oStreamReader object
oStreamReader.Dispose();
dataGridView5.DataSource = result.Tables[oDataTable.TableName];
}
Here is the Code:
private void button9_Click(object sender, EventArgs e)
{
try
{
DataClasses1DataContext conn = new DataClasses1DataContext();
else if (textBox3.Text.Contains("GEN_EX"))
{
foreach (DataTable dt in result.Tables)
{
foreach (DataRow dr in dt.Rows)
{
GEN_EX addtable = new GEN_EX()
{
EX_ID = Convert.ToByte(dr[0]),
DOC_ID = Convert.ToByte(dr[1]),
PATIENT_NO = Convert.ToByte(dr[2]),
TEST_DATE = Convert.ToDateTime(dr[3]),
**TEST_TIME = Convert.ToDateTime((dr[4])),**
};
conn.GEN_EXs.InsertOnSubmit(addtable);
}
}
conn.SubmitChanges();
MessageBox.Show("File uploaded successfully");
}
else
{
MessageBox.Show("I guess table is not coded yet");
}
}
EDIT
The TEST_TIME represents HH:MM:SS
The Typed Data Set is defined as:
public virtual int Update(
byte EX_ID,
byte DOC_ID,
byte PATIENT_NO,
System.DateTime TEST_DATE,
System.TimeSpan TEST_TIME)
Based on your input that dr[4] represents time values in hours:minutes:seconds format I recommend following solution.
private TimeSpan GetTimeSpan(string timeString)
{
var timeValues = timeString.Split(new char[] { ':' });
//Assuming that timeValues array will have 3 elements.
var timeSpan = new TimeSpan(Convert.ToInt32(timeValues[0]), Convert.ToInt32(timeValues[1]), Convert.ToInt32(timeValues[2]));
return timeSpan;
}
Use above method as following.
else if (textBox3.Text.Contains("GEN_EX"))
{
foreach (DataTable dt in result.Tables)
{
foreach (DataRow dr in dt.Rows)
{
GEN_EX addtable = new GEN_EX()
{
EX_ID = Convert.ToByte(dr[0]),
DOC_ID = Convert.ToByte(dr[1]),
PATIENT_NO = Convert.ToByte(dr[2]),
TEST_DATE = Convert.ToDateTime(dr[3]),
**TEST_TIME = GetTimeSpan(dr[4].ToString()),**
};
conn.GEN_EXs.InsertOnSubmit(addtable);
}
}
conn.SubmitChanges();
MessageBox.Show("File uploaded successfully");
}
This should give your the value you want. You will face runtime issues if value of dr[4] is not in hours:minutes:seconds format. That I will leave it up to you.
First of all Timespan and DateTime are 2 differents type without implicit conversion available. Since Timespan is a time value between two DateTime, you need to know your referenced time (DateTime) used to start the mesure of your Timespan.
For example it could be from DateTime dtReferential = new DateTime(1900, 01, 01);
In order to give a SQL Timespan value you need to give it a C# Timespan! Change TEST_TIME value to a Timespan. And finally, give it the substracted value of your referenced time.
Using the previous example:
else if (textBox3.Text.Contains("GEN_EX"))
{
foreach (DataTable dt in result.Tables)
{
foreach (DataRow dr in dt.Rows)
{
GEN_EX addtable = new GEN_EX()
{
EX_ID = Convert.ToByte(dr[0]),
DOC_ID = Convert.ToByte(dr[1]),
PATIENT_NO = Convert.ToByte(dr[2]),
TEST_DATE = Convert.ToTimespan(dr[3]),
TEST_TIME = dtReferential.Subtract(Convert.ToDateTime(dr[4]))
};
conn.GEN_EXs.InsertOnSubmit(addtable);
}
}
conn.SubmitChanges();
MessageBox.Show("File uploaded successfully");
}

C# Reading CSV file with SQL conditions

I am using CsvHelper lib to read CSV file and I can successfully read the file with the lib. However I cannot use SQL condition to filter values. How can I do that without using SQL Server. I am really stuck on it.
It was very easy with Pandas and Pandasql libs in Python but it is being too hard in C#..
My Code:
public static void Main(string[] args)
{
var fileInfo = new FileInfo(#"filePath");
using (TextReader reader = fileInfo.OpenText())
using (var csvReader = new CsvReader(reader))
{
csvReader.Configuration.Delimiter = ",";
csvReader.Configuration.HasHeaderRecord = false;
csvReader.Configuration.IgnoreQuotes = true;
csvReader.Configuration.TrimFields = true;
csvReader.Configuration.WillThrowOnMissingField = false;
while (csvReader.Read())
{
var myStrinVar = csvReader.GetField<string>(0);
Console.Write(myStrinVar); //SELECT * FROM table...
}
}
}
I would suggest using LINQ to filter your results.
https://msdn.microsoft.com/en-us/library/bb397906.aspx
Say you have some class MyClass that you can serialize the lines in your file into.
For example:
public class MyClass
{
public int ID { get; set; }
}
var records = csv.GetRecords<MyClass>().ToList();
var filtered = records.Where(r => r.ID >= 10);
That example is a bit contrived but you can use any boolean expression you like in the where clause.
I know this is too late for OP, but the issue with the accepted answer is that you have to read in the entire result set to memory which may not be tenable for large files. Also, if you can extend this code below to get the top N rows without having to read the entire CSV if you find matches early in the file.
public static void Main(string[] args)
{
var fileInfo = new FileInfo(#"filePath");
var where = ""; //Code to set up where clause part of query goes here
using (TextReader reader = fileInfo.OpenText())
using (var csvReader = new CsvReader(reader))
{
csvReader.Configuration.Delimiter = ",";
csvReader.Configuration.HasHeaderRecord = false;
csvReader.Configuration.IgnoreQuotes = true;
csvReader.Configuration.TrimFields = true;
csvReader.Configuration.WillThrowOnMissingField = false;
DataTable dt = null;
while (csvReader.Read())
{
//Use the first row to initialize the columns.
if (dt == null)
{
dt = new DataTable();
for (var i = 0; i < csvReader.FieldCount; i++)
{
var fieldType = csvReader.GetFieldType(i);
DataColumn dc;
if (fieldType.IsNullableType())
{
dc = new DataColumn(csvReader.GetName(i), Nullable.GetUnderlyingType(fieldType));
dc.AllowDBNull = true;
}
else
dc = new DataColumn(csvReader.GetName(i), data.GetFieldType(i));
dt.Columns.Add(dc);
}
}
//Map DataReader to DataRow
var newRow = dt.Rows.Add();
foreach(DataColumn col in dt.Columns)
{
newRow[col.ColumnName] = csvReader[col.ColumnName];
}
//Create a temporary DataView and filter it with the where clause.
DataView dv = new DataView(dt);
dv.RowFilter = where;
var data = dv.Count > 0 ? dv[0] : null;
if(data != null)
{
//Row in here matches your where clause.
//Code to read this row or do something with it.
}
//Empty the temporary data table.
dt.Rows.Clear();
}
}
}

Loading User Control Dynamically

I have my code as below
string[] keys = { "myCustomUserControl.ascx", "myCustomUserControl.ascx.cs", "myCustomUserControl.ascx.designer.cs" };
string customUserControlName = CommonDataCalls.GetCustomUserControlName(keys);
UserControl objUserControl = (UserControl)this.LoadControl("~/UserControls/" + userControlName);
userControlPlaceHolder.Controls.Add(objUserControl);
The definition of GetCustomUserControlName is as below
public string GetCustomUserControlName(string[] keys)
{
try
{
string userConrolsPhysicalPtah = System.Web.HttpContext.Current.Server.MapPath("~/UserControls/");
DataTable objDataTable = new DataTable();
foreach (string key in keys)
{
objRequestVO.addObject("ACA_KEY", key);
CResponseVO objResponseVO = (CResponseVO)objGateway.ExecuteBusinessService(CConstant.ADMIN, CConstant.ASSEMBLY_INFO, CConstant.SELECT, objRequestVO);
DataSet objDataSet = (DataSet)objResponseVO.getObject("RES_DS");
cUserTrce objGeneral = new cUserTrce();
if (!objGeneral.IsNullOrEmptyDataset(objDataSet))
{
if (objDataTable.Rows.Count == 0)
{
objDataTable = objDataSet.Tables[0].Clone();
}
objDataTable.Rows.Add(objDataSet.Tables[0].Rows[0].ItemArray);
}
}
if (objDataTable != null && objDataTable.Rows.Count == 3)
{
string containerName = "usercontrols";
foreach (DataRow dr in objDataTable.Rows)
{
string userControlFileBlobUrl = dr["ACA_ASSEMBLY_PATH"].ToString();
string userControlFileName = dr["ACA_CLASS_NAME"].ToString();
Storage.Blob blobHandler = new Storage.Blob();
Stream blobstream = blobHandler.GetBlob(userControlFileBlobUrl, containerName);
if (!(File.Exists(userConrolsPhysicalPtah + userControlFileName)))
{
MemoryStream ms = (MemoryStream)blobstream;
FileStream outStream = File.OpenWrite(userConrolsPhysicalPtah + userControlFileName);
ms.WriteTo(outStream);
outStream.Flush();
outStream.Close();
}
}
string customUserControlName = (from DataRow row in objDataTable.Rows
where row["ACA_KEY"].ToString() == keys[0]
select row["ACA_CLASS_NAME"].ToString()).First();
return customUserControlName;
}
else
{
return null;
}
}
catch
{
return null;
}
}
The mithod basically copies the user controls to the virtual path at run time .
In aspx.cs page I try to load it dynamically .
But I can see the file is getting copied to the virtual path but this. Load control gives me exception saying Could not load type 'myCustomUserControl'.
I am using azure web role
What is wrong here ?
I solved the bug . I am just putting here for anyone to refer .
It's a one word change -
http://blog.kjeldby.dk/2008/11/dynamic-compilation-in-a-web-application/
Change
CodeBehind="myCustomUserControl.ascx.cs"
to
CodeFile="myCustomUserControl.ascx.cs"
Thanks to #Roopesh & #Kristoffer Brinch Kjeldby
and it will start working.

Retrieve Dynamics CRM custom fields using Webservice query

I'm trying to pull information from a CRM installation and so far this is fine for using the default fields. However I'm having difficulty retrieving custom fields, for example Contacts have a custom field called web_username.
My code at present is
QueryExpression query = new QueryExpression();
query.EntityName = "contact";
ColumnSet cols = new ColumnSet();
cols.Attributes = new string[] { "firstname", "lastname" };
query.ColumnSet = cols;
BusinessEntityCollection beReturned = tomService.RetrieveMultiple(query);
foreach (contact _contact in beReturned.BusinessEntities)
{
DataRow dr = dt.NewRow();
dr["firstname"] = _contact.firstname;
dr["lastname"] = _contact.lastname;
dt.Rows.Add(dr);
}
How do I include custom fields in my query? I've tried searching around but with no luck yet but I could be searching incorrectly as I'm not used to CRM terms.
Cheers in advance!
I've since been able to solve this. In case it is of use to anyone else this is what I did. The query is set up as before except I've added my custom field to the ColumnSet.
cols.Attributes = new string[] { "firstname", "lastname", "new_web_username" };
And then used RetrieveMultipleResponse and Request with ReturnDynamicEntities set to true
RetrieveMultipleResponse retrived = new RetrieveMultipleResponse();
RetrieveMultipleRequest retrive = new RetrieveMultipleRequest();
retrive.Query = query;
retrive.ReturnDynamicEntities = true;
retrived = (RetrieveMultipleResponse)tomService.Execute(retrive);
Please still comment if there is a better way for me to do this.
EDIT
Using the example in my original question if you cast to a contact
contact myContact = (contact)myService.Retrieve(EntityName.contact.ToString(), userID, cols);
You can then access properties of the object
phone = myContact.telephone1;
password = myContact.new_password;
If you update your CRM webreference custom fields you've added in CRM are available.
public List<Entity> GetEntitiesCollection(IOrganizationService service, string entityName, ColumnSet col)
{
try
{
QueryExpression query = new QueryExpression
{
EntityName = entityName,
ColumnSet = col
};
var testResult = service.RetrieveMultiple(query);
var testResultSorted = testResult.Entities.OrderBy(x => x.LogicalName).ToList();
foreach (Entity res in testResultSorted)
{
var keySorted = res.Attributes.OrderBy(x => x.Key).ToList();
DataRow dr = null;
dr = dt.NewRow();
foreach (var attribute in keySorted)
{
try
{
if (attribute.Value.ToString() == "Microsoft.Xrm.Sdk.OptionSetValue")
{
var valueofattribute = GetoptionsetText(entityName, attribute.Key, ((Microsoft.Xrm.Sdk.OptionSetValue)attribute.Value).Value, _service);
dr[attribute.Key] = valueofattribute;
}
else if (attribute.Value.ToString() == "Microsoft.Xrm.Sdk.EntityReference")
{
dr[attribute.Key] = ((Microsoft.Xrm.Sdk.EntityReference)attribute.Value).Name;
}
else
{
dr[attribute.Key] = attribute.Value;
}
}
catch (Exception ex)
{
Response.Write("<br/>optionset Error is :" + ex.Message);
}
}
dt.Rows.Add(dr);
}
return testResultSorted;
}
catch (Exception ex)
{
Response.Write("<br/> Error Message : " + ex.Message);
return null;
}
}
//here i have mentioned one another function:
var valueofattribute = GetoptionsetText(entityName, attribute.Key, ((Microsoft.Xrm.Sdk.OptionSetValue)attribute.Value).Value, _service);
//definition of this function is as below:
public static string GetoptionsetText(string entityName, string attributeName, int optionSetValue, IOrganizationService service)
{
string AttributeName = attributeName;
string EntityLogicalName = entityName;
RetrieveEntityRequest retrieveDetails = new RetrieveEntityRequest
{
EntityFilters = EntityFilters.All,
LogicalName = entityName
};
RetrieveEntityResponse retrieveEntityResponseObj = (RetrieveEntityResponse)service.Execute(retrieveDetails);
Microsoft.Xrm.Sdk.Metadata.EntityMetadata metadata = retrieveEntityResponseObj.EntityMetadata;
Microsoft.Xrm.Sdk.Metadata.PicklistAttributeMetadata picklistMetadata = metadata.Attributes.FirstOrDefault(attribute => String.Equals(attribute.LogicalName, attributeName, StringComparison.OrdinalIgnoreCase)) as Microsoft.Xrm.Sdk.Metadata.PicklistAttributeMetadata;
Microsoft.Xrm.Sdk.Metadata.OptionSetMetadata options = picklistMetadata.OptionSet;
IList<OptionMetadata> OptionsList = (from o in options.Options
where o.Value.Value == optionSetValue
select o).ToList();
string optionsetLabel = (OptionsList.First()).Label.UserLocalizedLabel.Label;
return optionsetLabel;
}

Categories