My statement:
string sqlCommandText = "SELECT * FROM ForumThread WHERE";
How can I read * from it?
I'm trying like this but its doesnt work:
if (reader["*"] != DBNull.Value)
{
result.TextContent = Convert.ToString(reader["*"]);
}
* is not a column, it's a instruction to SELECT to just grab every column it can find.
The columns will appear individually though, so you need to iterate through the columns one by one and grab their contents.
To get the column contents, you can do this:
StringBuilder sb = new StringBuilder();
for (int index = 0; index < reader.FieldCount; index++)
{
object value = reader[index];
if (value != DBNull.Value)
sb.Append(value.ToString());
}
result.TextContent = sb.ToString();
However, this will result in everything being mashed together.
For instance, if your result set look like this:
A B C D
10 20 30 Some name here
Then your resulting string will look like this:
102030Some name here
Is this what you want?
Perhaps you told us what you want to accomplish, we can think of a better answer?
Additionally, you can use this method to retrieve the associated field name:
reader.GetName( /* index of the column */);
Suppose your ForumThread table contains the ThreadResponse column, and you actually want to read the ThreadResponse column, you can use the next code:
//calculates the column ordinal based on column name
int ThreadResponseColumnIdx = reader.GetOrdinal("ThreadResponse");
//If there is a line in the result
if (reader.Read())
{
//read from the current line the ThreadResponse column
result.TextContent = reader.GetString(ThreadResponseColumnIdx);
}
Related
How can I more efficiently check for null values and set their order accordingly?
I have 3 fields (1, 2, 3) and I need to do a check to see if any of the string values are null and if so I need to move the respective value up to the next spot so if 2 is null but 3 is not I will need to move 3 into 2's spot.
My original thought was to do this with a series of if statements however after starting down that road I'm learning that my list of if statements is going to be substantial so I'm looking for a better way to preform this check and set my values.
if (string.IsNullOrEmpty(field1))
{
fields.SetField("Field1", field1);
fields.SetField("Field2", field2);
}
If I continued down the above route I would have to also preform a check for field 2 and 3 and etc... for each initial check.
Maybe you could use this logic:
string firstNotNull = field1 ?? field2 ?? field3;
if (string.IsNullOrEmpty(field1)) fields.SetField("Field1", firstNotNull);
if (string.IsNullOrEmpty(field2)) fields.SetField("Field2", firstNotNull);
if (string.IsNullOrEmpty(field3)) fields.SetField("Field3", firstNotNull);
But the logic is not entirely clear. Do you also want to overwrite Field3 with a value from Field1 if the Field3 is null and Field1 not?
Maybe this generic approach is what you're looking for:
var stringColumns = table.Columns.Cast<DataColumn>().Where(c => c.DataType == typeof(string)).ToList();
foreach (DataRow row in table.Rows)
{
for (int i = 0; i < stringColumns.Count; i++)
{
string field = row.Field<string>(i);
if (string.IsNullOrEmpty(field))
{
// check all after this:
for (int ii = i + 1; ii < stringColumns.Count; ii++)
{
string nextField = row.Field<string>(ii);
if (!string.IsNullOrEmpty(nextField))
{
row.SetField(i, nextField);
break;
}
}
}
}
}
If 'fields' is an IEnumerable collection of strings, you could simply call the Orderby() / OrderByDescending() method on it.
var sortedFields = fields.OrderBy(s => s);
// OR
var sortedFields = fields.OrderByDescending(s => s)
I have a small program where you can select some database tables and create a excel file with all values for each table and thats my solution to create the excel file.
foreach (var selectedDatabase in this.lstSourceDatabaseTables.SelectedItems)
{
//creates a new worksheet foreach selected table
foreach (TableRetrieverItem databaseTable in tableItems.FindAll(e => e.TableName.Equals(selectedDatabase)))
{
_xlWorksheet = (Excel.Worksheet) xlApp.Worksheets.Add();
_xlWorksheet.Name = databaseTable.TableName.Length > 31 ? databaseTable.TableName.Substring(0, 31): databaseTable.TableName;
_xlWorksheet.Cells[1, 1] = string.Format("{0}.{1}", databaseTable.TableOwner,databaseTable.TableName);
ColumnRetriever retrieveColumn = new ColumnRetriever(SourceConnectionString);
IEnumerable<ColumnRetrieverItem> dbColumns = retrieveColumn.RetrieveColumns(databaseTable.TableName);
var results = retrieveColumn.GetValues(databaseTable.TableName);
int i = 1;
(result is a result.Item3 is a List<List<string>> which contains all values from a table and for each row is a new list inserted)
for (int j = 0; j < results.Item3.Count(); j++)
{
int tmp = 1;
foreach (var value in results.Item3[j])
{
_xlWorksheet.Cells[j + 3, tmp] = value;
tmp++;
}
}
}
}
It works but when you have a table with 5.000 or more values it will take such a long time.
Does someone maybe know a better solution to add the List List string per row than my for foreach solution ?
I utilize the GetExcelColumnName function in my code sample to convert from column count to the excel column name.
The whole idea is, that it's very slow to write excel cells one by one. So instead precompute the whole table of values and then assign the result in a single operation. In order to assign values to a two dimensional range, use a two dimensional array of values:
var rows = results.Item3.Count;
var cols = results.Item3.Max(x => x.Count);
object[,] values = new object[rows, cols];
// TODO: initialize values from results content
// get the appropriate range
Range range = w.Range["A3", GetExcelColumnName(cols) + (rows + 2)];
// assign all values at once
range.Value = values;
Maybe you need to change some details about the used index ranges - can't test my code right now.
As I see, youd didn't do profiling. I recomend to do profiling first (for example dotTrace) and see what parts of your code actualy causing performance issues.
In my practice there is rare cases (almost no such cases) when code executes slower than database requests, even if code is realy awfull in algorithmic terms.
First, I recomend to fill up your excel not by columns, but by rows. If your table has many columns this will cause multiple round trips to database - it is great impact to performance.
Second, write to excel in batches - by rows. Think of excel files as mini-databases, with same 'batch is faster than one by one' principles.
I have a renderTable and I am adding rows and columns to the table as follows-
RenderTable renderTable = new RenderTable();
DataTable dt = GetData();
foreach (DataRow row in dt.Rows)
{
var header = renderTable.Rows[renderTable.Rows.Count];
header[0].Text = "Column 1";
header[1].Text = "Column 2";
header[2].Text = "Column 3";
header[1].Text = "Column 4";
var data = renderTable.Rows[renderTable.Rows.Count];
data [0].Text = row["col1"].ToString(); // 10
data [1].Text = row["col2"].ToString(); // 11
data [2].Text = row["col3"].ToString(); // 12
data [3].Text = row["col4"].ToString(); // 13
}
This is working fine and table is rendering as folllows-
Column 1 Column2 Column3 Column4
10 11 12 13
My requirement is, now I want to move the column 4 to another place like 2nd place as follows . (this place can differ depending on condition)
Column 1 Column4 Column2 Column3
10 13 11 12
I tried Insert method but it is not working for me as the insert index may change.
Is there any function of render table to move the column to specified index.
Please suggest any alternative if any.
We regret to mention but there isn't any function that can allow the moving of column of RenderTable to a specified index since the Cols of C1PrintDocument is ReadOnly.
I've done this by creating a new class from System.Web.UI.WebControls.GridView. I override CreateColumns which is used to return an array of the column objects in order. I read a cookie from the page (this allows me to change the columns via a cookie on the page) and create a new column array based on the cookie. This cookie is just a string of the column names in the order required with a | separator. I had another column picker page that would set this cookie. If you don't need to change the columns with a cookie this is not needed -- you could read / create this string from a database or configuration file. I believe the code is well commented and clear -- one note, our application has a requirement to include hidden columns, so I add those to the end of the column list before I return the array.
using System.Collections;
using System.Linq;
using System.Web.UI.WebControls;
public class ChangeColumnGridView : System.Web.UI.WebControls.GridView
{
protected override ICollection CreateColumns(PagedDataSource dataSource, bool useDataSource)
{
// Get the needful from the base class
var baseColList = base.CreateColumns(dataSource, useDataSource);
var inColList = baseColList.OfType<object>();
// Get our column order
string columnOrder;
if (Page.Request.Cookies["colOrder"] != null)
columnOrder = Page.Request.Cookies["colOrder"].Value;
else
return baseColList;
// change it to an array
string[] columnOrderA = columnOrder.Split(new char[] { '|' });
// this is where we will put our results
ArrayList newColumnList = new ArrayList();
// look for each name in the list and add when we find it.
foreach (string name in columnOrderA)
{
var found = inColList.Where((c) => c.ToString() == name).FirstOrDefault();
if (found != null)
newColumnList.Add(found);
}
// look for non-visible items in the list and add them if we don't already have them.
foreach (var a in inColList)
{
if (((System.Web.UI.WebControls.DataControlField)a).Visible == false)
{
var found = newColumnList.Cast<object>().Where((c) => c.ToString() == a.ToString()).FirstOrDefault();
if (found == null)
newColumnList.Add(a);
}
}
return newColumnList;
}
}
I have a flat file with an unfortunately dynamic column structure. There is a value that is in a hierarchy of values, and each tier in the hierarchy gets its own column. For example, my flat file might resemble this:
StatisticID|FileId|Tier0ObjectId|Tier1ObjectId|Tier2ObjectId|Tier3ObjectId|Status
1234|7890|abcd|efgh|ijkl|mnop|Pending
...
The same feed the next day may resemble this:
StatisticID|FileId|Tier0ObjectId|Tier1ObjectId|Tier2ObjectId|Status
1234|7890|abcd|efgh|ijkl|Complete
...
The thing is, I don't care much about all the tiers; I only care about the id of the last (bottom) tier, and all the other row data that is not a part of the tier columns. I need normalize the feed to something resembling this to inject into a relational database:
StatisticID|FileId|ObjectId|Status
1234|7890|ijkl|Complete
...
What would be an efficient, easy-to-read mechanism for determining the last tier object id, and organizing the data as described? Every attempt I've made feels kludgy to me.
Some things I've done:
I have tried to examine the column names for regular expression patterns, identify the columns that are tiered, order them by name descending, and select the first record... but I lose the ordinal column number this way, so that didn't look good.
I have placed the columns I want into an IDictionary<string, int> object to reference, but again reliably collecting the ordinal of the dynamic columns is an issue, and it seems this would be rather non-performant.
I ran into a simular problem a few years ago. I used a Dictionary to map the columns, it was not pretty, but it worked.
First make a Dictionary:
private Dictionary<int, int> GetColumnDictionary(string headerLine)
{
Dictionary<int, int> columnDictionary = new Dictionary<int, int>();
List<string> columnNames = headerLine.Split('|').ToList();
string maxTierObjectColumnName = GetMaxTierObjectColumnName(columnNames);
for (int index = 0; index < columnNames.Count; index++)
{
if (columnNames[index] == "StatisticID")
{
columnDictionary.Add(0, index);
}
if (columnNames[index] == "FileId")
{
columnDictionary.Add(1, index);
}
if (columnNames[index] == maxTierObjectColumnName)
{
columnDictionary.Add(2, index);
}
if (columnNames[index] == "Status")
{
columnDictionary.Add(3, index);
}
}
return columnDictionary;
}
private string GetMaxTierObjectColumnName(List<string> columnNames)
{
// Edit this function if Tier ObjectId is greater then 9
var maxTierObjectColumnName = columnNames.Where(c => c.Contains("Tier") && c.Contains("Object")).OrderBy(c => c).Last();
return maxTierObjectColumnName;
}
And after that it's simply running thru the file:
private List<DataObject> ParseFile(string fileName)
{
StreamReader streamReader = new StreamReader(fileName);
string headerLine = streamReader.ReadLine();
Dictionary<int, int> columnDictionary = this.GetColumnDictionary(headerLine);
string line;
List<DataObject> dataObjects = new List<DataObject>();
while ((line = streamReader.ReadLine()) != null)
{
var lineValues = line.Split('|');
string statId = lineValues[columnDictionary[0]];
dataObjects.Add(
new DataObject()
{
StatisticId = lineValues[columnDictionary[0]],
FileId = lineValues[columnDictionary[1]],
ObjectId = lineValues[columnDictionary[2]],
Status = lineValues[columnDictionary[3]]
}
);
}
return dataObjects;
}
I hope this helps (even a little bit).
Personally I would not try to reformat your file. I think the easiest approach would be to parse each row from the front and the back. For example:
itemArray = getMyItems();
statisticId = itemArray[0];
fileId = itemArray[1];
//and so on for the rest of your pre-tier columns
//Then get the second to last column which will be the last tier
lastTierId = itemArray[itemArray.length -1];
Since you know the last tier will always be second from the end you can just start at the end and work your way forwards. This seems like it would be much easier than trying to reformat the datafile.
If you really want to create a new file, you could use this approach to get the data you want to write out.
I don't know C# syntax, but something along these lines:
split line in parts with | as separator
get parts [0], [1], [length - 2] and [length - 1]
pass the parts to the database handling code
I have a collection of string names, few names starts with X100,x200,x121 which has numeric values.
I'm using LinQ to loop thro and also using a where clause to filter those names that has integer values like x"100." Which is the best way to do accompolish this?.
is it possible to use Func or Action on the items for checking each string variable.My
where clause in expression looks something like this
var columns = from c in factory.GetColumnNames("eventNames")
where c.Substring(1) // I dont know what to do next
select c;
.if the next string is "c.substring(1)" integer obviously the names are wrong.So is there any best way to do this check and return a string collection
To find all strings that contain an integer, you could use
var columns = from c in factory.GetColumnNames("eventNames")
where Regex.IsMatch(c, #"\d+")
select c;
Try this to select all the rows that are like "x100" etc.
int tmp;
var columns = from c in factory.GetColumnNames("eventNames")
where int.TryParse(c.Substring(1), out tmp)
select c;
Try this to select all rows, converting "x100" to "100" and leaving the rest as is.
int tmp;
var columns = from c in factory.GetColumnNames("eventNames")
select (int.TryParse(c.Substring(1), out tmp) ? tmp.ToString() : c);
If neither of these are what you want please clarify.
Try something like:
var columns = from c in factory.GetColumnNames("eventNames")
where CharactersAfterFirstAreInteger(c)
select c;
private bool CharactersAfterFirstAreInteger(string stringToCheck)
{
var subString = stringToCheck.SubString(1);
int result = 0;
return int.TryParse(subString, out result);
}
This gives you the flexibility to alter the signature of CharactersAfterFirstAreInteger, if you needed to, so you could perform additional checks, for example, so that only values where the numeric part were greater than 200 were returned..