I have a class that derives from DataTable. In its ctor, I'd like it to have all the data from a DataTable object I fetch from a call to a function.
This sounds like a very trivial thing but I am surprised that I can't figure it out. Sorry, I've been coding for over 12 hours straight and so I think I am phased out.
Help will be appreciated.
using System.Data;
using Foo.Data;
namespace Foo.BusinessObjects
{
public class StringTable : DataTable
{
public StringTable() : base()
{
var sql = "SELECT * FROM FooBar";
// I know that that's not a legal C# statement but
// if it were, I'd want to do the equivalent of the following:
this = Database.DefaultDatabase.GetDataTable(sql);
}
}
}
Where the GetDataTable method returns a System.Data.DataTable object. It's signature is here:
public DataTable GetDataTable(string sql, params SqlParameter[] parameters)
{
DataSet dataset;
return ((dataset = GetDataSetInternal(sql, false, parameters)) == null ?
null : dataset.Tables[0]);
}
You can replace the below line in the constructor of the derived class
this = Database.DefaultDatabase.GetDataTable(sql);
with
DataTable dtResult = Database.DefaultDatabase.GetDataTable(sql);
this.Merge(dtResult);
You cannot do this kind of thing in a constructor. You could favour composition over inheritance and still have your StringTable class.
public class StringTable
{
private DataTable dataTable;
public StringTable()
{
var sql = "SELECT * FROM FooBar";
// I know that that's not a legal C# statement but
// if it were, I'd want to do the equivalent of the following:
dataTable = Database.DefaultDatabase.GetDataTable(sql);
}
}
Another option is look towards factory patterns working with DataTable rather than subclassing it. Something along these lines. Inheritance is really only to give you benefit if it can behave in polymorphic way. Otherwise I am not sure you gain anything,
public class DataTableFactory
{
public DataTable CreateStringTable()
{
var sql = "SELECT * FROM FooBar";
DataTable dataTable = new DataTable();
return Database.DefaultDatabase.GetDataTable(sql);
}
public DataTable CreateSomeOtherTable()
{
//etc etc
}
}
Related
So, I'm writing a method to get tables from a database. I want to make it dynamic to avoid writing a new method for each table. it's something like this:
public static List<?> LoadTable(string TableName, Class class)
{
using (IDbConnection cnn = new SQLiteConnection(LoadConnectionString()))
{
var output = cnn.Query<class>("select * from " + TableName, new DynamicParameters());
return output.ToList();
}
}
now the problem is, when I write "List<dynamic>" instead of the "List<?>" it can't convert the class to dynamic. also the parameter "Class class" is not valid obviously. how can I get a class type like that? "Type" doesn't work either as you know.
Thanks to #MartinCostello and #PanagiotisKanavos comments, we come to a great answer for my simple but frustrating problem:
public static List<T> LoadTable<T>(string TableName)
{
using (IDbConnection cnn = new SQLiteConnection(LoadConnectionString()))
{
var output = cnn.Query<T>("select * from " + dBTable, new DynamicParameters());
return output.ToList();
}
}
Then you can call it like this:
dataGrid.ItemsSource = LoadTable<TableClass>("TableName");
I've been using dapper lately and wanted to make a dynamic method that would make it easier to select things out with sql.
This is my code:
Class:
public class Method
{
public static IEnumerable<dynamic> QueryAll(string table)
{
dynamic dyn = table;
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["DbCon"].ToString());
using (con)
{
string sql = String.Format("SELECT * FROM {0}", table);
IEnumerable<dynamic> ie = con.Query<dynamic>(sql, null);
return ie;
}
}
}
Calling function here:
IEnumerable<posts> = Method.QueryAll("posts");
It gives me an error that I cannot convert IEnumerable dynamic to IEnumerable Models.Posts.
How can I cast it to make it work.
Technically you could just use the IEnumerable.Cast-method to cast every instance returned from the method to the actual instance.
IEnumerable<posts> = Method.QueryAll("posts").Cast<posts>();
However if you allready know the the actual type why not use it in the query allready? dynamic should be handled with care and only if your really have to, which I doubt is the case here. You could for example add the actual type as type-parameter to the method:
public static IEnumerable<T> QueryAll<T>(string table)
{
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["DbCon"].ToString());
using (con)
{
string sql = String.Format("SELECT * FROM {0}", table);
IEnumerable<T> ie = con.Query<T>(sql, null);
return ie;
}
}
Now you can call it as follows:
var result = Method.QueryAll<posts>("posts");
As an aside Method is a really bad class-name, as posts also. You should give your class names that describe what they serve for and what they are doing. Moreover there are naming-conventions suggesting to use PascalCase-names for class making your class Posts. At last when you have an enumeration of posts, I suppose the class itself represents one single post, not many, so you actual want a class named Post which you can store into an IEnumerable<Post>.
I have the following class which I am using to read in large amounts of data from an Access database.
public class ConnectToAccess
{
private readonly string _connectionString;
public ConnectToAccess(String connectionString)
{
_connectionString = connectionString;
}
public List<String> GetData(String sql)
{
var data = new List<String>();
using (var connection = new OleDbConnection(_connectionString))
{
using (var command = connection.CreateCommand())
{
command.CommandText = sql;
command.CommandType = CommandType.Text;
connection.Open();
using (var reader = command.ExecuteReader())
{
if (reader != null && reader.HasRows)
while (reader.Read())
{
data.Add(reader["First Name"] + " " + reader["Last Name"]);
}
}
}
}
return data;
}
}
As is, this code is working and is successfully pulling data in from the database. However, I would like to enhance the GetData() method to make it more dynamic. I would like it to somehow return a list of anonymous objects, where each object has properties relating to the columns of the dataset returned.
I've been coding in .Net for a while, but I'm still rather new at many concepts. I'm not quite sure how to create this list of anonymous objects that mirror the columns in the dataset most effectively. I'm also not sure what return type I would use in this case, I'm thinking maybe List. Then I suppose I would need to use reflection to pull the data out of those anonymous objects and transfer it into where it needs to go.
If anyone can help me with any significant part of this puzzle, I would be most obliged.
You can't have an anonymous type as a return type.
Why not just return a DataTable. You can even use a DataAdapter to make the process a lot easier. It also gets you the schema.
If you insist on getting objects for everything:
public IEnumerable<T> GetData(String sql, Func<DataReader, T> selector)
{
//code elided
while (reader.Read())
{
yield return selector(reader);
}
}
Now you can use it with a selector:
var people = GetData("Select * from People", reader => new Person { Name = reader{"Name"], Age = reader["Age"] })
people.Take(5); //first five records only
I have a DataGridView with
myGridView.DataSource = GetSomeData()
// method called
public IQueryable GetSomeData()
{
var source = from r in records
select r;
return source; // made correction from 'r' to 'source'
}
GetSomeData() fills the DataGridView as expected. The user will select a row to edit which then passes the row data to a form. Since the DataGridViewRow.DataBoundItem is an anonymous type, how can I pass DataBoundItem?
I half expected that my DataBoundItem would be IQueryable - incorrect. Here is the info from the debugger on the DataBoundItem property:
DataBoundItem { CustomerID = "3133",
Last_Name = "Smith", First_Name =
"John", AccountNumber = "JS3133",
ActiveYN = True } < Anonymous Type >
Once the data is passed to the new form, I would like to do something like:
txtFName.Text = SomeEnumeratedObject["First_Name"];
txtLName.Text = SomeEnumeratedObject["Last_Name"];
Any ideas on how I can do this? It would be even better, IMO, if the controls on the new form could some how be bound to SomeEnumeratedObject.
Would it possible to query the DataBoundItem with LINQ?
Edit:
Changed method:
public DataView GetSomeData()
{
var source = from r in records
select r;
DataTable table = ToDataTable(myContext, source);
return new DataView(table);
}
See complete solution here.
You could pass it as dynamic and access the properties that way:
public void Test(dynamic item)
{
MessageBox.Show(string.Format("{0} : {1}", item.First_Name, item.Last_Name));
textBox1.DataBindings.Add("Text", _item, "First_Name");
textBox2.DataBindings.Add("Text", _item, "Last_Name");
}
One thing to consider is that properties on anonymous types are read only, so your user will not be able to edit the values that way. From the C# Language Spec:
The members of an anonymous type are a sequence of read-only properties inferred from the anonymous object initializer used to create an instance of the type.
You should consider declaring a type for this instead of using an anonymous type. That way you'll also get the benefit of intellisense and be able to rename/refactor your properties without any problems.
What type of objects are in records? You should be able to cast DataGridViewRow.DataBoundItem to whatever type of object records holds.
Say records is a list of Customer objects. You should be able to go:
txtFName.Text = ((Customer)DataGridViewRow.DataBoundItem).First_Name;
txtLName.Text = ((Customer)DataGridViewRow.DataBoundItem).Last_Name;
If that isn't possible, then I think you will have to use reflection:
Type type = DataGridViewRow.DataBoundItem.GetType();
String firstName = (String)type.GetProperty("First_Name")
.GetValue(DataGridViewRow.DataBoundItem, null);
Both kevev22 & adrift had the right idea: create a class to hold the data. Since I can transform an IQueryable resultset to a DataTable, it only made sense to do that:
public DataView GetSomeData()
{
var source = from r in records
select r;
DataTable table = ToDataTable(myContext, source);
return new DataView(table);
}
Now:
myDGView.DataSource = GetSomeData();
And, when a datagrid row is selected, you can cast the DataBoundItem to DataRow.
FYI - to transform an IQueryable resultset to a DataTable:
public DataTable ToDataTable(DataContext context, IQueryable source)
{
DataTable table = new DataTable();
{
adapter.SelectCommand = context.GetCommand(source);
sqlCommand.Connection.Open();
adapter.FillSchema(table, SchemaType.Source);
adapter.Fill(table);
}
return table;
}
What is the easiest way to convert an IQueryable object to a dataset?
modelshredder has exactly what you need. If you have the datacontext around and don't need the data in terms of your model also, nitzmahone' solution is fine performance wise (if it matches your setup, which is not clear to me)
(yourDatacontext).GetCommand(yourIQueryableHere), pass command text to a DbCommand object, call ExecuteReader, pass reader to dataset's .Load method.
The easiest thing to do might be to write an implementation of IDataReader that can wrapper an IEnumerable (IQueryable is an IEnumberable). There is an implementation here. Then you can call DataTable.Load(IDataReader).
If you create a DataTable from schema so it matches your LINQ to Sql, I have an extension method that takes the IQueryable and fills the DataTable:
public static DataTable AsDataTable(this IQueryable value, DataTable table)
{
var reader = value.GetEnumerator();
while (reader.MoveNext())
{
var record = (Customer)reader.Current;
table.Rows.Add(record.CustomerID, record.City);
}
return table;
}
Note that the cast to Customer is my TEntity:
[Table(Name = "Customers")]
public class Customer
{
[Column(IsPrimaryKey = true)]
public string CustomerID;
[Column]
public string City;
}
There are other options that use reflection to build your DataTable from the Customer class. Given the performance hit from reflection, I chose to use the following method to build my table:
public DataTable GetSchema(params string[] columns)
{
string col_list;
if (columns.Length == 0)
col_list = "*";
else
col_list = String.Join(", ", columns);
return Provider.QueryAsDataTable(string.Format("select top 0 {0} from customers", col_list));
}
Putting all that together, I was able to push the results into my DataGridView:
dgridRO.DataSource = new DataView(rows.AsDataTable(dmap.GetSchema("CustomerID", "City")));
**
ID10TException:
**
I spent all this effort getting a conversion from the IQueryable to a DataTable just so I could create a DataView as a source to the DataGridView. Well, I know I didn't need to do that now.