Very frustrated here ...
I can usually find an answer of some kind to complex issues in .Net somewhere on the net, but this one eludes me.
I'm in a scenario where I have to convert the result of a LINQ to Entity query into a DataSet so the data can then be processed by existing business logic, and I can't find a single working solution out ther for this.
I've tried basic approaches like the EntityCommand generating a reader, but this one does not work because DataTable.Load() thorws an excpetion (the reader generated by EntityCommand does not support GetSchemaTable() ).
I've also tried more [supposedly] friendly approaches like Entity to IDataReader(http://l2edatareaderadapter.codeplex.com/), but this one throws exceptions, has very little docs, and hasn't been touched since 2008.
Another approach I found is here (http://blogs.msdn.com/b/alexj/archive/2007/11/27/hydrating-an-entitydatareader-into-a-datatable-part-1.aspx), but does not have a working copy of the code; only snippets.
I find it hard to believe that first of all MS would not have offered this backwards-compatibility item out of the box, and second, that it would not have been created by the community either.
I'm willing to look at commercial solutions as well if any are available.
Thx!
You can convert the result into a list and use the following to convert the list to a datatable.
public DataTable ConvertToDataTable<T>(IList<T> data)
{
PropertyDescriptorCollection properties =
TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
foreach (PropertyDescriptor prop in properties)
table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
foreach (T item in data)
{
DataRow row = table.NewRow();
foreach (PropertyDescriptor prop in properties)
row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
table.Rows.Add(row);
}
return table;
}
http://social.msdn.microsoft.com/Forums/br/csharpgeneral/thread/6ffcb247-77fb-40b4-bcba-08ba377ab9db
Hope this helps
Preetam
This might not be the greatest solution, but if your scenario have only one or two table that you need to add to the DataSet, why not build them directly manually.
var result = db.YourTable; // get your Linq To Entities result.
DataSet ds = new DataSet();
DataTable tbl = new DataTable();
tbl.Columns.Add("col1", typeof(string));
tbl.Columns.Add("col2", typeof(int));
foreach (var r in result)
{
var row = tbl.NewRow();
row[0] = r.Col1;
row[1] = r.Col2;
tbl.Rows.Add(r);
}
ds.Tables.Add(tbl);
The Col1 and Col2 comes from your Linq To Entity objects, you can create all the table you need like this and return your DataSet.
This is a flexible code and should handle most of your needs:
public DataTable LINQToDataTable<T>(IEnumerable<T> varlist)
{
DataTable dtReturn = new DataTable();
// column names
PropertyInfo[] oProps = null;
if (varlist == null) return dtReturn;
foreach (T rec in varlist)
{
// Use reflection to get property names, to create table, Only first time, others will follow
if (oProps == null)
{
oProps = ((Type)rec.GetType()).GetProperties();
foreach (PropertyInfo pi in oProps)
{
Type colType = pi.PropertyType;
if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>)))
{
colType = colType.GetGenericArguments()[0];
}
dtReturn.Columns.Add(new DataColumn(pi.Name, colType));
}
}
DataRow dr = dtReturn.NewRow();
foreach (PropertyInfo pi in oProps)
{
dr[pi.Name] = pi.GetValue(rec, null) == null ? DBNull.Value : pi.GetValue
(rec, null);
}
dtReturn.Rows.Add(dr);
}
return dtReturn;
}
Related
There are many tables in the database that are used as "lookup" tables. All the tables have the same structure, other than the ID column name.
I have found that I can use reflection to open a table and enumerate through the records. The method takes a string (tableName).
Uri serviceUri = new Uri("http://localhost/MyDataService/WcfDataService.svc");
var context = new MyEntities(serviceUri);
var eTable = typeof(MyEntities).GetProperty(tableName).GetValue(context, null) as IEnumerable<object>
foreach (object o in eTable)
...
This works fine, but I want to add a WHERE clause to the query. For example, where InactiveDate == null.
Can I do this? I have been unable to figure this one out.
How about this?
var eTable = (typeof(MyEntities).GetProperty(tableName).GetValue(context, null) as IEnumerable<object>).Where(obj => obj.GetType().GetProperty("InactiveDate").GetValue(obj) == null);
foreach (object o in eTable)
I would suggest to use generics and maybe an interface over reflection.
public function Xyz<TEntity>(Func<MyEntities, IDbSet<TEntity>> dbSetGetter, Expression<Func<TEntity, Boolean>> filter)
{
var serviceUri = new Uri("http://localhost/MyDataService/WcfDataService.svc");
using (var context = new MyEntities(serviceUri))
{
foreach (var entity in dbSetGetter(context).Where(filter))
{
DoSomethingWith(entity);
}
}
}
Usage would be like this
Xyz(context => context.Foo, foo => foo.Bar == 42);
assuming you have an entity Foo with an integer property Bar. The obvious difference to your code is that you have to know the entity type a compile time and I am not sure if you know it then.
I have a SQL Database which I imported as a ADO.NET Entity Data Model. I then populate a DataGridView using Linq. I extended two of the tables with extra columns that are calculated from other tables. For instance, I have a table Orders that has fields OrderNumber, DateApproved and RequestorID and so on. I also have a table that is the OrderDetails with Fields like SKU, OrderNUmber and QuanityOrdered. I coded a new column IsBackOrdered for the Orders Table that calculates if any Item(SKU) from the OrderDetails is backordered.
When I bound the table Orders to the DataGridView.DataSource everything works as expected. I was then directed to create a search filter for the table.
I tried to map BindingSource to the Linq query but BindingSource is expecting a DataTable. I found a neat little method that converts Linq ResultSet to a DataTable (Code below) however it barfs on my custom fields (Columns) at this line: dr[pi.Name] = pi.GetValue(rec, null) ?? DBNull.Value;
Thanks in advance for any of your view or helpful insights you would care to offer.
public static DataTable LinqToDataTable<T>(IEnumerable<T> varlist)
{
var dtReturn = new DataTable();
// column names
PropertyInfo[] oProps = null;
if (varlist == null)
return dtReturn;
foreach (T rec in varlist)
{
// Use reflection to get property names, to create table, Only first time, others will follow
if (oProps == null)
{
oProps = rec.GetType().GetProperties();
foreach (PropertyInfo pi in oProps)
{
Type colType = pi.PropertyType;
if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>)))
{
colType = colType.GetGenericArguments()[0];
}
dtReturn.Columns.Add(new DataColumn(pi.Name, colType));
}
}
DataRow dr = dtReturn.NewRow();
foreach (PropertyInfo pi in oProps)
{
dr[pi.Name] = pi.GetValue(rec, null) ?? DBNull.Value;
}
dtReturn.Rows.Add(dr);
}
return dtReturn;
}
DataSource property of the BindingSource doesn't expect DataTable. It's of type object, so you may use any list as data source. But in this case to be able to filter it you should either implement IBindingListView or use BindingList. The second case is easier of course. Take a look here for more information.
I've looked at the various solutions here but none of them seem to work for me, probably because I'm too new to all this and am groping in the dark a bit. In the code below, the object "appointment" contains some basic LDAP information. From a list of such objects I want to be able to get a single record, based on employee id. I hope the code here is sufficient to illustrate. FTR, I've tried various formulations, including trying to use from and a select. All fail with the error given in the Title above.
IQueryable<appointment> query = null;
foreach(var record in results)
{
BoiseStateLdapDataObject record1 = record;
query = db.appointments.Where(x => x.student_id == record1.Values["employeeid"]);
}
if (query != null)
{
var selectedRecord = query.SingleOrDefault();
}
Try to move employee id getting out of query:
IQueryable<appointment> query = null;
foreach(var record in results)
{
var employeeId = record.Values["employeeid"];
query = db.appointments.Where(x => x.student_id == employeeId);
}
if (query != null)
{
var selectedRecord = query.SingleOrDefault();
}
I am using entityframework. I had two records which are retrieved from table using 'id' which is a primary key. Now i want to compare these two table records data and display the old value and new value in my view. Now my question is how to compare two records... There are almost 20 properties in my table from which i retrieve the data. We have to compare each and every property or is there are any best method... Can any one please help me to find the solution..
public bool Equals<T>(T first, T second)
{
var f = new List<T>() {first};
var s = new List<T>() {second};
PropertyInfo[] propertyInfos = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Static);
foreach (PropertyInfo propertyInfo in propertyInfos)
{
if (f.Select(x => propertyInfo.Name).FirstOrDefault() != s.Select(x => propertyInfo.Name).FirstOrDefault())
return false;
}
return true;
}
Changed to Equals < T > (T first, T second) as Kim R recommended
Try it :) I haven't tested it
Is it possible to get the column names directly from a datacontext? Below I'm just hard coding the DataTextField and DataValueField, but I'd like to be able to get them from the datacontext if possible. What is the recommended way of getting the column names in a strongly-typed way?
DataClassesDataContext db = new DataClassesDataContext(WebConfigurationManager.ConnectionStrings[connstring].ConnectionString);
drdPriority.DataSource = db.Tasks;
drdPriority.DataTextField = "TaskDescription";
drdPriority.DataValueField = "TaskId";
drdPriority.DataBind();
Try the following code:
using (DataContext1.DataContext1 dc = new DataContext1.DataContext1()) {
var q = dc.Mapping.GetTables();
foreach (System.Data.Linq.Mapping.MetaTable table in q) {
List names = new List();
foreach (System.Data.Linq.Mapping.MetaDataMember member in table.RowType.DataMembers) {
names.Add(member.Name);
}
//Process the names here
}