Linq Query Using DataTable with Paging - linq

I have a Linq query that I copy to a DataTable which is then used to populate a gridview. I am using a group by "key" and "count" which I evaluate in the aspx page for a master/detail gridview with a repeater.
The problem that I am encountering is that the gridview datasource and bind to the datatable is not presenting me with any additional pages that are part of the data.
My query is:
// Using Linq generate the query command from the DataTable
var query = from c in dtDataTable_GridView.AsEnumerable()
group c by c.Field<string>("CLIN") into g
select new
{
Key = g.Key,
Count = g.Count(),
Items = from i in g
select new
{
CLIN = i.Field<string>("CLIN"),
SLIN = i.Field<string>("SLIN"),
ACRN = i.Field<string>("ACRN"),
CLINType = i.Field<string>("CLINType"),
Option = i.Field<string>("Option"),
Unit = i.Field<string>("Unit")
}
};
// Use extension methods to create new DataTable from query
dtTaskOrderTable = query.CopyToDataTable();
// Set the datasource
gridview1.DataSource = dtTaskOrderTable;
// Bind to the GridView
gridview1.DataBind();
If I use the original datatable (dtDataTable_GridView) directly I have paging but once I do the Linq Query and copy it back to a new datatable (dtTaskOrderTable) I lose the paging feature.
Also how do I get a value from a column name ("Option" for instance) if it is part of "Items"?
Any help would be appreciated.
Thanks,
ChrisB

Please disregard the previous answer I will delete it
It requires ICollection interface for paging.
Neither IEnumerable nore IQuerable will not work
List<(Of <(T>)>) will work as Lists implement Icollection interface
So you need
gridview1.DataSource = dtTaskOrderTable.ToList();

Related

Select multiple column in Linq using List

I have a DropDownList and I fill it using linq. The code example below is working.
ddlPortal.DataSource = from rows in db.Portals select new
{rows.Id, rows.PortalName};
But I need to use it with List variable. What's the problem about the code below?
ddlPortal.DataSource = new List<string>(from rows in db.Portals select new {rows.Id.ToString(), rows.PortalName});
By the way I need to retrieve two columns for DataValueField and DataTextField of DropDownList .
That's not a List<string> but a list of an anonymous type. Use var:
var dataSource = db.Portals
.Select(rows => new {Id = rows.Id.ToString(),Portal = rows.PortalName} )
.ToList();
ddlPortal.DataSource = dataSource;

Linq ResultSet to DataTable

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.

LINQ to Entities does not recognize the method 'Boolean CheckMeetingSettings(Int64, Int64)' method

I am working with code first approach in EDM and facing an error for which I can't the solution.Pls help me
LINQ to Entities does not recognize the method 'Boolean
CheckMeetingSettings(Int64, Int64)' method, and this method cannot be
translated into a store expression.
My code is following(this is the query which I have written
from per in obj.tempPersonConferenceDbSet
where per.Conference.Id == 2
select new PersonDetials
{
Id = per.Person.Id,
JobTitle = per.Person.JobTitle,
CanSendMeetingRequest = CheckMeetingSettings(6327,per.Person.Id)
}
public bool CheckMeetingSettings(int,int)
{
///code I have written.
}
Please help me out of this.
EF can not convert custom code to SQL. Try iterating the result set and assigning the property outside the LINQ query.
var people = (from per in obj.tempPersonConferenceDbSet
where per.Conference.Id == 2
order by /**/
select new PersonDetials
{
Id = per.Person.Id,
JobTitle = per.Person.JobTitle,
}).Skip(/*records count to skip*/)
.Take(/*records count to retrieve*/)
.ToList();
people.ForEach(p => p.CanSendMeetingRequest = CheckMeetingSettings(6327, p.Id));
With Entity Framework, you cannot mix code that runs on the database server with code that runs inside the application. The only way you could write a query like this, is if you defined a function inside SQL Server to implement the code that you've written.
More information on how to expose that function to LINQ to Entities can be found here.
Alternatively, you would have to call CheckMeetingSettings outside the initial query, as Eranga demonstrated.
Try:
var personDetails = obj.tempPersonConferenceDbSet.Where(p=>p.ConferenceId == 2).AsEnumerable().Select(p=> new PersonDetials
{
Id = per.Person.Id,
JobTitle = per.Person.JobTitle,
CanSendMeetingRequest = CheckMeetingSettings(6327,per.Person.Id)
});
public bool CheckMeetingSettings(int,int)
{
///code I have written.
}
You must use AsEnumerable() so you can preform CheckMeetingSettings.
Linq to Entities can't translate your custom code into a SQL query.
You might consider first selecting only the database columns, then add a .ToList() to force the query to resolve. After you have those results you van do another select where you add the information from your CheckMeetingSettings method.
I'm more comfortable with the fluid syntax so I've used that in the following example.
var query = obj.tempPersonConferenceDbSet
.Where(per => per.Conference.Id == 2).Select(per => new { Id = per.Person.Id, JobTitle = per.Person.JobTitle })
.ToList()
.Select(per => new PersonDetails { Id = per.Id,
JobTitle = per.JobTitle,
CanSendMeetingRequest = CheckMeetingSettings(6327, per.Person.Id) })
If your CheckMeetingSettings method also accesses the database you might want to consider not using a seperate method to prevent a SELECT N+1 scenario and try to express the logic as part of the query in terms that the database can understand.

WPF BindingListCollectionView to ListCollectionView for DataTable as ItemsSource

I want to do custom sorting on a ListView which has a DataTable as ItemsSource:
myListView.ItemsSource = (data as DataTable);
And this are the first lines of my sorting function:
DataView view = (myListView.ItemsSource as DataTable).DefaultView;
ListCollectionView coll = (ListCollectionView)CollectionViewSource.GetDefaultView(view);
The second line throws an execption like:
Unable to cast "System.Windows.Data.BindingListCollectionView" to "System.Windows.Data.ListCollectionView"
Has anyone a solution? Thx 4 answers
It returns an ICollectionView that is not a ListCollectionView. You most likely want a view on top of a view to get the features that ListCollectionView has. And since ICollectionView implements CollectionChanged, you wouldn't want to use BindingListCollectionView.
DataView view = (myListView.ItemsSource as DataTable).DefaultView;
ListCollectionView coll = new ListCollectionView(CollectionViewSource.GetDefaultView(view));
Although an alternative would be:
DataView view = (myListView.ItemsSource as DataTable).DefaultView;
BindingListCollectionView coll = new BindingListCollectionView(view);
If you only wanted only one view.
If you are binding directly to a WPF control, it is best to bind directly to it without making a BindingListCollectionView/ListCollectionView, as DefaultView already allows sorting of the DataTable.
Binding binding = new Binding() { Source = (myListView.ItemsSource as DataTable) };
this.myListView.SetBinding(myListView.ItemsSourceProperty, binding);
DataView view = (myListView.ItemsSource as DataTable).DefaultView;
view.Sort = "Age";
Hopefully Helpful,
TamusJRoyce

linq help - newbie

how come this work
public IQueryable<Category> getCategories(int postId)
{
subnusMVCRepository<Categories> categories = new subnusMVCRepository<Categories>();
subnusMVCRepository<Post_Category_Map> postCategoryMap = new subnusMVCRepository<Post_Category_Map>();
var query = from c in categories.GetAll()
join pcm in postCategoryMap.GetAll() on c.CategoryId equals pcm.CategoryId
where pcm.PostId == 1
select new Category
{
Name = c.Name,
CategoryId = c.CategoryId
};
return query;
}
but this does not
public IQueryable<Category> getCategories(int postId)
{
subnusMVCRepository<Categories> categories = new subnusMVCRepository<Categories>();
subnusMVCRepository<Post_Category_Map> postCategoryMap = new subnusMVCRepository<Post_Category_Map>();
var query = from c in categories.GetAll()
join pcm in postCategoryMap.GetAll() on c.CategoryId equals pcm.CategoryId
where pcm.PostId == postId
select new Category
{
Name = c.Name,
CategoryId = c.CategoryId
};
return query;
}
The issue is most likely in the implementation of the query provider.
pcm.PostId == 1
and
pcm.PostId == postId
actually have a big difference. In the expression tree the first is generated as a ConstantExpression which doesnt need to be evaulated.
With the second, the compiler actually generates an inner class here (this is the _DisplayClassX that you see). This class will have a property (will most likely be the same name as your parameter) and the expression tree will create a MemberAccessExpression which points to the auto-generated DisplayClassX. When you query provider comes accross this you need to Compile() the Lambda expression and evaluate the delegate to get the value to use in your query.
Hope this helps.
cosullivan
The problem is not the linq itself,
you need to be sure that the context or provider object is able to fetch the data.
try testing the
subnusMVCRepository<Categories> categories = new subnusMVCRepository<Categories>();
subnusMVCRepository<Post_Category_Map> postCategoryMap = new subnusMVCRepository<Post_Category_Map>();
objects and see if they are populated or if they behaving as required.
you may want to search the generated code for c__DisplayClass1 and see what you can see there. some times the generated code dose some weird things.
when you step into you code check the locals and the variable values. this may also give you some clues.
Edit : Have you tried to return a List<> collection ? or an Enumerable type?
Edit : What is the real type of the item and query may not be iterable

Resources