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.
Related
So i have a DataSet to query a table on an Oracle Database. The table is very large and has 3.5 million entries. However later in the code I filter this table on a few hundred entries that are necessary.
AgileDataSet agileDataSet = new AgileDataSet();
AgileDataSetTableAdapters.UserDataTableAdapter userDataTableAdapter = new AgileDataSetTableAdapters.UserDataTableAdapter();
userDataTableAdapter.Fill(agileDataSet.UserData);
var l=agileDataSet.UserData.Where(x=>x.ID==1234);
Due to the large amount of entries the Fill() method takes forever. Is there a way to add a conditions to the fill method at runtime. Adding a permanent WHERE clause to the TableAdapter's SQL Statement in the DataSet Designer is not an option, because I do not know beforehand which elements are needed.
Ok so I implemented a hacky "solution" and created a new partial class for the TableAdapter. In this class I generated an adapted Fill-Function to use whenever I need to get a subset of the whole DBTable in my DataTable
partial class UserDataTableAdapter
{
public virtual int FillByCICList(AgileDataSet.UserDataDataTable dataTable, List<long> cics)
{
this.CommandCollection[0].CommandText += String.Format(" WHERE vu.C_IC IN ({0})", String.Join(", ", cics));
this.Adapter.SelectCommand = this.CommandCollection[0];
if ((this.ClearBeforeFill == true))
{
dataTable.Clear();
}
int returnValue = this.Adapter.Fill(dataTable);
this.InitCommandCollection();
return returnValue;
}
}
This function takes a list of c_ics as additional input and adds a where condition to the base commanttext used for the standard fill function.
Calling it would look sth like this:
List<long> c_ics = new List<long>{224,484,966,695,918};
userDataTableAdapter.FillByCICList(agileDataSet.UserData, c_ics);
I am sure that there is a better solution to this, but that is all I got so far
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 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
}
}
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;
}
I get some informations in a Dataset, and i would like to cast it in a strongly type object.
For example my dataset have :
TableName : tab_data
Rows : 1
Columns : Name, FirstName, Address
So i created a class like :
public class Customer
{
public String Name;
public String FirstName;
public String Address;
}
Is there a magic trick to simply cast my dataset to Customer type ? Use LiNQ ?
Thanks,
Is there any reason you haven't created a strongly-typed DataSet to start with? That would probably be the easiest solution.
You can certainly convert each DataTable into (say) a List<Customer> using the AsEnumerable extension to DataTable and a projection which creates a Customer from a DataRow if you really need to.
You can't cast this, but you can translate the data...
The answer is probably different for 1 table than it is for 20; on an individual bases, you should just be able to Select out the data (or alternatively, just iterate) - this will be the fastest option, but is lots of maintenance if you have lots of tables. In the latter case, some kind of reflection, perhaps like so.
Here is example of how can you convert a Dataset into Strongly typed object. There are some situations where we get data into dataset through some other source which might not be strongly typed. But Dataset allows us to convert data into strongly typed object.
List<Customer> CustomerList =
(from row in ds.Tables[0].AsEnumerable()
select new Customer
{
Name = row.Field<string>("Name"),
FirstName = row.Field<string>("FirstName"),
Address = row.Field<string>("Address")
}).ToList();