Getting data from Database object without using foreach - c#

I understand this method of getting DB data (using foreach):
var db = Database.Open("Connection");
var rows = db.Query("SELECT 1 columnName,2 columnName2 FROM Table");
foreach(var row in rows){
var data = row.columnName;
//or
var data = row[0];
}
This works, but how do I get the data without using a foreach?
var data = rows[0][1];
^ This doesn't work.
Basically, I am trying to figure out how to get the data without using a foreach. What would I have to do?
EDIT:
.Query() returns:
Type: System.Collections.Generic.IEnumerable
The rows returned by the SQL query.
As shown here: http://msdn.microsoft.com/en-us/library/webmatrix.data.database.query%28v=vs.111%29.aspx

You can use the ElementAt method to get to the row then use indexing to get to the column of that row:
var data = rows.ElementAt(0)[0];
You can even reference the columns by name as you are actually receiving an IEnumerable<dynamic>:
var row = rows.ElementAt(0);
//now you can access:
//row.columnName
//row.columnName2

Using ToArray() on your collection is an option;
var results = db.Query("SELECT * FROM Table").ToArray();
Console.WriteLine(results[1][2]);
This will allow you to reference your result set the way you want. However, if you don't bound your collection in the query somehow, you could end up loading a large collection into memory to reference it this way. I've never seen the WebMatrix Database before, so I can't give any tips on doing this in the most efficient manner, but ToArray() will give you what you want.
db.Query actually returns type DynamicRecord, so if you want to reference your column names by name, you can do;
var results = db.Query("SELECT * FROM Table").Cast<DynamicRecord>().ToArray();
Console.WriteLine(results[0]["Id"]);
Now you can use column names
And as petelids mentions,
IEnumerable<dynamic> results = db.Query("SELECT * FROM Table");
Console.WriteLine(results.ElementAt(0).Id);

If you are wanting a specific answer for the WebMatrix.Data example, then this won't help you at all.
However, if you like writing actual SQL statements, but don't like tedious mapping code, then I like to use micro-ORMs like OrmLite, PetaPoco, Massive, Dapper, etc...
This is an example using my favorite: http://www.toptensoftware.com/petapoco/
http://www.nuget.org/packages/petapoco
/// <summary>
/// Create a Poco mapping class where the class name matches the Table name
/// and the properties match the column names and data types from the table
/// </summary>
public class Table{
public int ColumnName {get;set;}
public int ColumnName2 {get;set;}
}
int id = 1;
var db = new Database("Connection Name");
const string sql = #"SELECT
1 columnName,
2 columnName2
FROM Table
WHERE ColumnName = #0";
return db.FirstOrDefault<Table>(sql, id);
or
// Using auto-generated Select statement
return db.FirstOrDefault<Table>("WHERE ColumnName = #0", id);
// Fetch all records...
return db.Fetch<Table>("");
// PetaPoco also supports dynamic
return db.FirstOrDefault<dynamic>(sql, id);

What does db.Query returns is some information we need.
What you can try is fill your result in a datatable.
And then getting it back like this:
DataTable dt = db.Query("SELECT 1 columnName,2 columnName2 FROM Table");
string s= dt.Rows[0][1].ToString();
But to be honest as long as you can get 0 or more then 1 results back you want to use a loop to irate through.

If you are using DataTable use:
datatable.rows[0][1].toString()
or if you are using an IEnumerable object use
objectName[0].propertyName.toString()
Here the propertyName is the name of the property you are using for that DataColumn.
From http://msdn.microsoft.com/en-us/library/webmatrix.data.database.query%28v=vs.111%29.aspx i am seeing query method returns IEnumerable objects so you may need the second way.
Thank you

Related

Using a list retrieved from a SQLite query in a 'foreach' statement

I'm currently converting some code that stores data in an XML file to storing it in a SQLite database instead. The database has a single table with 4 columns:
thumbnail | title | threadid | url
All of the entries in the database are strings. With my old code, I extract all the data from an XML file and populate a datagrid with the values. My aim is to do just that but using data pulled from the SQLite database. I can successfully extract all the data from the database table like so:
public List<Database> getFromTable()
{
List<Database> items = new List<Database>();
string sql = "SELECT * FROM blacklist";
SQLiteCommand command = new SQLiteCommand(sql, m_dbConnection);
using (SQLiteDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
var item = new Database();
item.imgstring = (string)reader["thumbnail"];
item.titlestring = (string)reader["title"];
item.threadidstring = (string)reader["threadid"];
item.urlstring = (string)reader["url"];
items.Add(item);
}
}
return items;
}
The part I'm now stuck on is how to use the results returned in the list. Currently I'm calling the method like so:
var items = database.getFromTable();
However after failing to find some examples, I can't work out how to put the foreach line together use the items in the returned list. Eg;
foreach (??? in items)
{
// Populate line in datagrid with thumbnail, title, threadid, url
}
I can get the datagrid populated, it's just understanding how to breakdown my 'items' into a usable form. Any pointers appreciated.
Edit I will be adding this information into a data-grid so each cell value from the SQLite table will be added into a matching cell on the data-grid.
Edit 2 It's worth mentioning that while thumbnail from my SQLite database is a string value, it's actually an image that's been converted to a Base64ImageRepresentation so I can store it as a string value. Part of getting each value from the SQLite database is so I can convert this string back to an image before adding in into my DataGridView.
It would be easier to forego the custom objects, and instead just read a DataTable and use it as the source of the DataGridView directly.
If you must use the custom objects, then you will have to loop over them, create rows from the grid's data source, and populate the rows one by one, adding them back once populated.
Something like this:
foreach (var item in getFromTable())
{
var index = grid.Rows.Add();
var row = grid.Rows[index];
row.SetValues(item.imgstring, item.titlestring, item.threadidstring, item.urlstring); //order of the items must match field order in grid
}
Still, I would opt for the option of binding to a solid data source. But this should give you the general idea.

How do I use LINQ to update a datatable with a SqlDataReader?

I am trying to merge data from two separate queries using C#. The data is located on separate servers or I would just combine the queries. I want to update the data in one of the columns of the first data set with the data in one of the columns of the second data set, joining on a different column.
Here is what I have so far:
ds.Tables[3].Columns[2].ReadOnly = false;
List<object> table = new List<object>();
table = ds.Tables[3].AsEnumerable().Select(r => r[2] = reader.AsEnumerable().Where(s => r[3] == s[0])).ToList();
The ToList() is just for debugging. To summarize, ds.Tables[3].Rows[2] is the column I want to update. ds.Tables[3].Rows[3] contains the key I want to join to.
In the reader, the first column contains the matching key to ds.Tables[3].Rows[3] and the second column contains the data with which I want to update ds.Tables[3].Rows[2].
The error I keep getting is
Unable to cast object of type 'WhereEnumerableIterator1[System.Data.IDataRecord]' to type 'System.IConvertible'.Couldn't store <System.Linq.Enumerable+WhereEnumerableIterator1[System.Data.IDataRecord]> in Quoting Dealers Column. Expected type is Int32.
Where am I going wrong with my LINQ?
EDIT:
I updated the line where the updating is happening
table = ds.Tables[3].AsEnumerable().Select(r => r[2] = reader.AsEnumerable().First(s => r[3] == s[0])[1]).ToList();
but now I keep getting
Sequence contains no matching element
For the record, the sequence does contain a matching element.
You can use the following sample to achieve the join and update operation. Let's suppose there are two Datatables:
tbl1:
tbl2:
Joining two tables and updating the value of column "name1" of tbl1 from column "name2" of tbl2.
public DataTable JoinAndUpdate(DataTable tbl1, DataTable tbl2)
{
// for demo purpose I have created a clone of tbl1.
// you can define a custom schema, if needed.
DataTable dtResult = tbl1.Clone();
var result = from dataRows1 in tbl1.AsEnumerable()
join dataRows2 in tbl2.AsEnumerable()
on dataRows1.Field<int>("ID") equals dataRows2.Field<int>("ID") into lj
from reader in lj
select new object[]
{
dataRows1.Field<int>("ID"), // ID from table 1
reader.Field<string>("name2"), // Updated column value from table 2
dataRows1.Field<int>("age")
// .. here comes the rest of the fields from table 1.
};
// Load the results in the table
result.ToList().ForEach(row => dtResult.LoadDataRow(row, false));
return dtResult;
}
Here's the result:
After considering what #DStanley said about LINQ, I abandoned it and went with a foreach statement. See code below:
ds.Tables[3].Columns[2].ReadOnly = false;
while (reader.Read())
{
foreach (DataRow item in ds.Tables[3].Rows)
{
if ((Guid)item[3] == reader.GetGuid(0))
{
item[2] = reader.GetInt32(1);
}
}
}

C#: How can I select specific rows from the ResultsTable returned from a KeywordQuery?

I am trying to perform a two-pass search against a Sharepoint list. In the first pass, I am using a KeywordQuery to search against the index of all the items. In the second pass, I am applying column value filters chosen by a user by building a select statement.
ResultTableCollection rtc = kwqry.Execute();
ResultTable rt = rtc[ResultType.RelevantResults];
dt = new DataTable();
//Load Data Table
dt.Load(rt, LoadOption.OverwriteChanges);
DataRow[] rows = dt.Select("ColumnName1 = 'foo' AND ColumnName2 = 'bar'");
Where the columns could be multi-value lookup columns in a Sharepoint list. The first pass is working properly and returning the right number of matches in a DataTable. However, when I try to apply the Select statement, I get the following error: Cannot perform '=' operation on System.String[] and System.String. Converting the columns to a string instead of a string array results in the same error, as does using the IN operator.
Am I building my select statement incorrectly? How could I run my second pass filter on my DataTable?
Have you tried with LINQ?
DataTable t1 = new DataTable();
var rows = from x in t1.AsEnumerable()
where x.Field<string[]>("column1name").Contains("foo")
select x;
You have to specify the field type in the Where clause...
Hope it helps.
Try using this, it will work :
DataRow[] rows = dt.Select("(ColumnName1 = 'foo' AND ColumnName2 = 'bar')");

LINQ query not returning rows in string comparison

I'm new to writing LINQ queries, and I'm having trouble with string comparisons. I'm loading the data into a DataTable (confirmed that table in SQL DB and DataTable have same number of rows), but for some reason I can't find a value that I know exists in both.
The text box contains 'servername' while the datarows contain 'servername.mydomain.net', so here's what my code looks like
string strParameter = txtAutoComplete.ToString().ToLower();
//WUG TableAdapter and DataTable
dsCIInfoTableAdapters.DeviceTableAdapter taWUG;
taWUG = new dsCIInfoTableAdapters.DeviceTableAdapter();
dsCIInfo.DeviceDataTable dtWUG = new dsCIInfo.DeviceDataTable();
taWUG.Fill(dtWUG);
var qstWUG = (from row in dtWUG.AsEnumerable()
where row.Field<string>("sDisplayName").ToLower().Contains(strParameter)
select row.Field<string>("sDisplayName"));
Beleive in your LINQ statement dtWUG needs to be dtWUG.AsEnumerable(). Linq only works on data sources that implement the IEnumerable Interface.
You can debug it easier if you add some let statements where you can add breakpoints:
var qstWUG = (from row in dtWUG
let display = row.Field<string>("sDisplayName")
let lower = display.ToLower()
let contains = lower.Contains(strParameter)
where contains
select display).ToArray();
Also convert it to an array using .ToArray() at the end, will make it execute immediately (LINQ is lazy by paradigm, doesn't execute until it's needed), and also easier to look at in subsequent breakpoints.
Yeah, I feel stupid... I forgot to use the textbox.text to assign it to a string
string strParameter = txtAutoComplete.Text.ToLower();
//WUG TableAdapter and DataTable
dsCIInfoTableAdapters.DeviceTableAdapter taWUG;
taWUG = new dsCIInfoTableAdapters.DeviceTableAdapter();
dsCIInfo.DeviceDataTable dtWUG = new dsCIInfo.DeviceDataTable();
taWUG.Fill(dtWUG);
var qstWUG = (from row in dtWUG.AsEnumerable()
let display = row.Field<string>("sDisplayName")
where display.ToLower().Contains(strParameter)
select display).ToArray();

Linq To Sql returns value length instead of value

I just started teaching myself Linq to SQL today. I hardly know anything about linq. That being said, I have a query that i want to return a Name from my database. It is a varchar in the DB
var query = from a in FRESH.Customers
select a.CUSTOMER_NAME;
dataGridView1.DataSource = query;
This results in a gridview with a column named "Length" and displays the length of every name. If I change the query to select a everything displays fine. What am I doing wrong here?
The DataGridView will by default show all of the properties of the type in the list as columns. Since your query is returning a collection of strings and the only1 "property" of a string is Length it shows that as a column.
Try changing to
var query = from a in FRESH.Customers
select new {Name = a.CUSTOMER_NAME};
1Technically the indexer Chars is a "property" but the DataGridView must be clever enough not to use an indexer as a column.
Problem is in gridView, not in Linq - gridView looks for properties of objects in DataSource. And it binds to first found property. Thus it binds strings by Length property (its the only property which String object has).
Default approach for displaying strings in gridView is creating some wrapper, which will have property with string value:
public class StringValue
{
public string Value { get; set; }
}
When you create anonymous object, as #DStanley suggested, wrapper is created for you by Linq:
var query = from a in FRESH.Customers
select new { CustomerName = a.CUSTOMER_NAME};
GridView will look for properties in anonymous object, and it will find and use CustomerName property.

Categories