I am trying to import an XML invoice to SQL database. After some research, I have managed to put it in SQL database but it has x rows whereas it should be a single row and x columns. Most of the sources I have read had examples of XML tables with multiple rows and XML files themselves were much simpler than this invoice file I am working with. I am aware the issue is probably related with columnMapping but could not figure how to fix it. Any help is appreciated.
Unfortunately I can't share the original invoice but I have found something similar: http://docs.oasis-open.org/ubl/os-UBL-2.2/xml/UBL-Invoice-2.1-Example.xml
private void buttonImport_Click(object sender, EventArgs e){
string XMlFile = textBoxBrowse.Text;
if (File.Exists(XMlFile))
{
DataTable dt = CreateDataTableXML(XMlFile);
if (dt.Columns.Count == 0)
dt.ReadXml(XMlFile);
string Query = CreateTableQuery(dt);
SqlConnection con = new SqlConnection(strcon);
con.Open();
cmd.ExecuteNonQuery();
// Table Creation
cmd = new SqlCommand(Query, con);
int check = cmd.ExecuteNonQuery();
if (check != 0)
{
// Copy Data from DataTable to Sql Table
using (var bulkCopy = new SqlBulkCopy(con.ConnectionString, SqlBulkCopyOptions.KeepIdentity))
{
foreach (DataColumn col in dt.Columns)
{
bulkCopy.ColumnMappings.Add(col.ColumnName, col.ColumnName); }
bulkCopy.BulkCopyTimeout = 600;
bulkCopy.DestinationTableName = dt.TableName;
bulkCopy.WriteToServer(dt);
}
MessageBox.Show("Table Created Successfully");
}
con.Close();
}
}
public DataTable CreateDataTableXML(string XmlFile) {
XmlDocument doc = new XmlDocument();
doc.Load(XmlFile);
DataTable Dt = new DataTable();
try
{
Dt.TableName = GetTableName(XmlFile);
XmlNode NodeStruct = doc.DocumentElement.ChildNodes.Cast<XmlNode>().ToList()[0];
foreach (XmlNode columna in NodeStruct.ChildNodes)
{
Dt.Columns.Add(columna.Name, typeof(String));
}
XmlNode Files = doc.DocumentElement;
foreach (XmlNode File in Files.ChildNodes)
{
List<string> Values = File.ChildNodes.Cast<XmlNode>().ToList().Select(x => x.InnerText).ToList();
Dt.Rows.Add(Values.ToArray());
}
}
catch (Exception ex)
{
}
return Dt;
}
Related
So, I have a table called Curr. My primary key is CurrID (auto-increment) and I have Foreign Key CouID. My csv file looks like this:
|1|12345|
|2|23456|
Everytime I add values to my csv file, I will upload it in the database. Ex:
|1|12345|
|2|23456|
|3|12345|
|4|93821|
Now the problem is that I don't want it to be added because it's already in the database. The database should look like this:
|1|12345|
|2|23456|
|4|93821|
Please help me. Here's my code.
string csvPath = Server.MapPath("~/Files/") + Path.GetFileName(Curr_Upload.PostedFile.FileName);
Curr_Upload.SaveAs(csvPath);
DataTable dt = new DataTable();
dt.Columns.AddRange(new DataColumn[2] {new DataColumn("CurrID", typeof(int))
new DataColumn("CouID", typeof(int)) });
string csvData = File.ReadAllText(csvPath);
foreach (string row in csvData.Split('\n'))
{
if (!string.IsNullOrEmpty(row))
{
dt.Rows.Add();
int i = 0;
foreach (string cell in row.Split(','))
{
lbl_status.Text = row;
dt.Rows[dt.Rows.Count - 1][i] = cell;
i++;
}
}
}
using (connection = new SqlConnection(constring))
{
using (SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(constring))
{
sqlBulkCopy.DestinationTableName = "dbo.Curr";
connection.Open();
sqlBulkCopy.WriteToServer(dt);
connection.Close();
}
}
}
I am searching a PDF file for a keyword and returning the pages on which that keyword was found. If the keyword IS FOUND, I'm returning a list of pages and the fileName. However, if the keyword was NOT FOUND in the PDF file, I want to deleted the row in the datatable.
public DataTable dtPubSearchResultsFromFiles(string sqlQuery, string safeKeyword)
{
// Returns a datatable of publication search results based on PDF files.
SqlConnection con = new SqlConnection(getConnectionString());
SqlCommand cmd = new SqlCommand(sqlQuery, con);
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
dt.Columns.Add("Pages", typeof(string));
da.Fill(dt);
dt.PrimaryKey = new DataColumn[] { dt.Columns["publicationID"] };
foreach (DataRow row in dt.Rows)
{
//call search function to look for keyword
List<int> myPages = new List<int>();
string fileName = row["linkToPublicationPDF"].ToString();
myPages = ReadPdfFile(fileName, safeKeyword);
if (myPages.Count > 0)
{
string pagelist = "";
foreach (int page in myPages)
{
pagelist = pagelist + page + " ";
}
row["Pages"] = pagelist;
}
else
{
//remove/delete the row from the datatable if "myPages.Count" is 0
dt.Rows.Remove(row);
}
}
return dt;
}
When I add this ("dt.Rows.Remove(row)"), I get this error when the page is called "System.InvalidOperationException: Collection was modified; enumeration operation might not execute."
Suggestions? Comments? Fixes? All are welcome...
Bob
Your code is getting some data from the database such that your program can work with it.
The exception you're getting is because your you're modifying (by removing an element) the collection you're iterating on and that's not possible.
You can solve this by creating a temporary List where you store the rows you want to delete. Once you're done with the iteration you can iterate on the temporary list and remove what you decided you don't want anymore.
var toRemove = new List<DataRow>();
foreach (DataRow row in dt.Rows)
{
//call search function to look for keyword
List<int> myPages = new List<int>();
string fileName = row["linkToPublicationPDF"].ToString();
myPages = ReadPdfFile(fileName, safeKeyword);
if (myPages.Count > 0)
{
string pagelist = "";
foreach (int page in myPages)
{
pagelist = pagelist + page + " ";
}
row["Pages"] = pagelist;
}
else
{
//remove/delete the row from the datatable if "myPages.Count" is 0
toRemove.Add(row);
}
}
}
foreach (DataRow row toRemove.Add)
{
dt.Rows.Remove(row);
}
try a simple Delete
row.Delete();
then after the loop
dt.AcceptChanges();
but it will probably fail
see answer from mario
it may work if it is really only marking the row for deletion
I am trying to import an CSV file into the database using asp, this code is from http://www.aspsnippets.com/Articles/Import-Upload-CSV-file-data-to-SQL-Server-database-in-ASPNet-using-C-and-VBNet.aspx
try
{
//Upload and save the file
string csvPath = Server.MapPath("/upload/") + Path.GetFileName(FileUpload2.PostedFile.FileName);
FileUpload2.SaveAs(csvPath);
DataTable dt = new DataTable();
dt.Columns.AddRange(new DataColumn[3] { new DataColumn("Id", typeof(int)),
new DataColumn("Name", typeof(string)),
new DataColumn("Country",typeof(string)) }
);
string csvData = File.ReadAllText(csvPath);
foreach (string row in csvData.Split('\n'))
{
if (!string.IsNullOrEmpty(row))
{
dt.Rows.Add();
int i = 0;
foreach (string cell in row.Split(','))
{
dt.Rows[dt.Rows.Count - 1][i] = cell;
i++;
}
}
}
string consString = ConfigurationManager.ConnectionStrings["TOP2000_IAO4B_GROEP5ConnectionString"].ConnectionString;
using (SqlConnection con = new SqlConnection(consString))
{
using (SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(con))
{
//Set the database table name
sqlBulkCopy.DestinationTableName = "[Customers]";
con.Open();
sqlBulkCopy.WriteToServer(dt);
con.Close();
}
}
}
catch(Exception ex)
{
Response.Write(ex);
}
However, when i go into debug mode and i look what the value of string csvData is, it's an empty string :/ I'm wondering what causes this, because obviously no data is inserted this way.
this is the CSV
1,John Hammond,United States
2,Mudassar Khan,India
3,Suzanne Mathews,France
4,Robert Schidner,Russia
the CSV is really simple to make it easy, can anyone help me with this?
Since you mentioned on debug you see CsvData, I suspect the problem lies on csvData.Split('\n') statement.
I just modified that particular logic, should work for you.
try
{
//Upload and save the file
string csvPath = Server.MapPath("/upload/") + Path.GetFileName(FileUpload2.PostedFile.FileName);
FileUpload2.SaveAs(csvPath);
DataTable dt = new DataTable();
dt.Columns.AddRange(new DataColumn[3] { new DataColumn("Id", typeof(int)),
new DataColumn("Name", typeof(string)),
new DataColumn("Country",typeof(string)) });
foreach (string row in File.ReadAllLines(csvPath))
{
if (!string.IsNullOrEmpty(row))
{
dt.Rows.Add();
int i = 0;
foreach (string cell in row.Split(','))
{
dt.Rows[dt.Rows.Count - 1][i] = cell;
i++;
}
}
}
string consString = ConfigurationManager.ConnectionStrings["TOP2000_IAO4B_GROEP5ConnectionString"].ConnectionString;
using (SqlConnection con = new SqlConnection(consString))
{
using (SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(con))
{
//Set the database table name
sqlBulkCopy.DestinationTableName = "[Customers]";
con.Open();
sqlBulkCopy.WriteToServer(dt);
con.Close();
}
}
}
catch(Exception ex)
{
Response.Write(ex);
}
I guess your issue is with Splitting CSV data.
Try this code working code :
private string[] SplitString(string inputString)
{
System.Text.RegularExpressions.RegexOptions options = ((System.Text.RegularExpressions.RegexOptions.IgnorePatternWhitespace | System.Text.RegularExpressions.RegexOptions.Multiline)
| System.Text.RegularExpressions.RegexOptions.IgnoreCase);
Regex reg = new Regex("(?:^|,)(\\\"(?:[^\\\"]+|\\\"\\\")*\\\"|[^,]*)", options);
MatchCollection coll = reg.Matches(inputString);
string[] items = new string[coll.Count];
int i = 0;
foreach (Match m in coll)
{
items[i++] = m.Groups[0].Value.Trim('"').Trim(',').Trim('"').Trim();
}
return items;
}
How to insert the database access column in combobox, on button click?it has 1 column
Try this:
create a private method that get msaccess data and bind to a datatable:
private DataTable BindData()
{
using (var conn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0; Data Source=C:\YOURDB.mdb; PersSecurity Info=False;")) /your connectionsting
{
using (var dAd = new OleDbDataAdapter("select ID,column1 from Table ", conn)) //select query from your DB
{
var dSet = new DataTable();
try
{
conn.Open();
dAd.Fill(dSet);
return dSet;
}
catch
{
throw;
}
finally
{
if (conn.State == ConnectionState.Open) conn.Close();
}
}
}
}
Then on your button click Add
var dt = BindData();
cmbBox.DataSource = dt;
cmbBox.DisplayMember = "column1"; //Display Table Column on your DB
cmbBox.ValueMember = "ID";
See also:
The C# Station ADO.NET Tutorial
Regards
Here's the scenario:
I have a multiline text box that I'm reading each line into an array. I'm then looping through that array and sending each value to the stored proc one by one inside the loop and getting a status returned to tell whether it's valid or not.
The issue is I believe I'm overwriting the dataset variable and only populating the datagrid with the last value I retrieve. Is there a better way to achieve what im trying to do? If so, please explain.
protected void submitButton_Click(object sender, EventArgs e)
{
string textLines;
string[] textLine;
textLines = scannedCode.Text;
textLine = textLines.Split(Environment.NewLine.ToArray(), StringSplitOptions.RemoveEmptyEntries);
DataSet ds = null;
Database db = DatabaseFactory.CreateDatabase("ConnectionString");
DataSet ds2 = null;
Database db2 = DatabaseFactory.CreateDatabase("ConnectionString");
foreach (string s in textLine)
{
try
{
DbCommand command2 = db.GetStoredProcCommand("sel_InfoByID_p");
db2.AddInParameter(command2, "#pGuid", DbType.String, s);
ds2 = db2.ExecuteDataSet(command2);
DataGrid1.DataSource = ds2;
DataBind();
}
catch (Exception ex)
{
}
}
}
First, it is possible to merge two dataSets by using the DataSet.Merge method. It means, that you should create a new DataSet outside of the loop and then merge it to a DataSet created by the stored procedure. One more solution is to copy rows from one DataSet to another using the Table's ImportRow method. The latter solution looks better for me. Here is some sample code:
DataTable dt = new DataTable;
...
ds2 = db2.ExecuteDataSet(command2);
for(int i = 0; i < ds2.Tables[0].Rows.Count; i ++)
dt.ImportRow(ds2.Tables[0].Rows[i]);
...
DataGrid1.DataSource = dt;
DataGrid1.DataBind();
Create a DataTable outside and in your for loop add your returned row .
DataTable dt = new DataTable();
///...Add known columns here
Inside for loop add rows to table . After for loop bind table at once.
protected void submitButton_Click(object sender, EventArgs e)
{
string textLines;
string[] textLine;
textLines = scannedCode.Text;
textLine = textLines.Split(Environment.NewLine.ToArray(), StringSplitOptions.RemoveEmptyEntries);
DataSet ds = null;
Database db = DatabaseFactory.CreateDatabase("ConnectionString");
DataSet ds2 = null;
Database db2 = DatabaseFactory.CreateDatabase("ConnectionString");
DataTable dt = new DataTable();
///...Add known columns here
foreach (string s in textLine)
{
try
{
DbCommand command2 = db.GetStoredProcCommand("sel_InfoByID_p");
db2.AddInParameter(command2, "#pGuid", DbType.String, s);
DataRow myNewRow = db2.ExecuteDataSet(command2).tables[0].rows[0];
dt.Rows.Add(myNewRow);
}
catch (Exception ex)
{
}
}
DataGrid1.DataSource = dt;
DataBind();
}
Try This
DataTable obj_Tb=new DataTable();
obj_Tb.Columns.Add("ColumnName");
. //Add Columns as your requirement
.
.
foreach (string s in textLine)
{
try
{
DataRow objrow=obj_Tb.NewRow();
DbCommand command2 = db.GetStoredProcCommand("sel_InfoByID_p");
db2.AddInParameter(command2, "#pGuid", DbType.String, s);
ds2= db2.ExecuteDataSet(command2);
objrow["ColumnName"]=ds2.Table[0].Rows[RowNumber]["ColumnName"].tostring();
//Add Values to all columns as requirement
obj_Tb.Rows.Add(objrow);
}
catch (Exception ex)
{
}
}
DataGrid1.DataSource = obj_Tb;
DataGrid1.DataBind();
Actually your problem was that you are binding the grid on EACH iteration, else nothing wrong with the code. So rather than:
foreach (string s in textLine)
{
try
{
DbCommand command2 = db.GetStoredProcCommand("sel_InfoByID_p");
db2.AddInParameter(command2, "#pGuid", DbType.String, s);
ds2 = db2.ExecuteDataSet(command2);
DataGrid1.DataSource = ds2;
DataBind();
}
catch (Exception ex)
{
}
}
do this:
foreach (string s in textLine)
{
try
{
DbCommand command2 = db.GetStoredProcCommand("sel_InfoByID_p");
db2.AddInParameter(command2, "#pGuid", DbType.String, s);
ds2 = db2.ExecuteDataSet(command2);
}
catch (Exception ex)
{
}
}
DataGrid1.DataSource = ds2;
DataBind();
However, since you're doing looping on the same functionality, for optimizing i suggest:
SqlConnection connection = new SqlConnection(ConnectionString);
SqlCommand command = new SqlCommand("MyStoredProcName", connection);
command.CommandType = CommandType.StoredProcedure;
SqlParameter submitParam = new SqlParameter("#pGuid", SqlDbType.String);
//use SqlDbType.Bit if you are returning true/false.
SqlParameter returParameter = new SqlParameter("#ReturnedParam", SqlDbType.String);
returParameter.Direction = ParameterDirection.Output;
connection.Open();
foreach (string s in textLine)
{
returnString.Value = s;
command.Parameters.Clear();
command.Parameters.Add(submitParam);
command.Parameters.Add(returParameter);
try
{
command.ExecuteNonQuery();
store the returned string in DataTable, BindingList<string> or any, but this is how to retrieve it:
Convert.ToString(Command.Parameters["#ReturnedParam"].Value, CultureInfo.CurrentCulture)
}
catch (Exception ex)
{
;;
}
}
connection.Close();
Do the grid binding here