I have an existing project where I want to use an ObjectDataSource
for a large data set which pages the results for a DevExpress Grid.
Examples of the code are shown below.
I am having trouble using an Entity Framework context in static methods that are required for the ObjectDataSource.
My problem is that I get this exception:
System.ObjectDisposedException: The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
Does anyone know how I can change the below to support passing an Entities
instance from the Page to the static methods?
This is the example of the ObjectDataSource
<dx:ASPxGridView ID="DefinedReportGrid" runat="server" EnableTheming="True" Theme="Office2010Blue" EnableViewState="False"
ClientInstanceName="DefinedReportGrid" DataSourceForceStandardPaging="True" DataSourceID="ReportDataSource">
<SettingsPager PageSize="30"></SettingsPager>
</dx:ASPxGridView>
<asp:ObjectDataSource ID="ReportDataSource" runat="server" EnablePaging="True"
StartRowIndexParameterName="startRecord" MaximumRowsParameterName="maxRecords" SelectCountMethod="GetPageCount" SelectMethod="GetData"
TypeName="ReportService">
</asp:ObjectDataSource>
This is my service class with static methods that can then be used by the ObjectDataSource
public class ReportService
{
[DataObjectMethod(DataObjectMethodType.Select, true)]
public static DataTable GetData(int startRecord, int maxRecords)
{
// Use EF DbContent and LINQ Query to fetch paged data, and return a DataTable
// The data is PIVOTED in the code before returning it as a DataTable
return outputTable;
}
public static List<int> GetWeeks()
{
// This also requires use of the EF DbContent
...
}
public static int GetPageCount()
{
// This also requires use of the EF DbContent
// Used to count the full data for applying the correct total Page Count
...
}
}
This is the code behind for the web forms page
public partial class DefinedReport : System.Web.UI.Page
{
private Entities _modelContext = ((Global)HttpContext.Current.ApplicationInstance).Entities;
protected void Page_Init(object sender, EventArgs e)
{
...
}
protected void Page_Load(object sender, EventArgs e)
{
...
}
}
This is the global code, where the Entities context is being set on the begin and end of the request.
public class Global : HttpApplication
{
public Entities Entities { get; set; }
...
private void Application_BeginRequest(object sender, EventArgs e)
{
Entities = new Entities();
}
private void Application_EndRequest(object sender, EventArgs e)
{
if (Entities != null)
{
Entities.Dispose();
}
}
}
As someone who uses the DevX grid quite a bit in a VB.Net Webforms app with static/Shared methods to encapsulate various data access logic, another approach would be to skip creating a ObjectDataSource
in the ASPX and instead set up the grid's DataSourceID
in the code-behind's Page_Load. I founded this much more manageable and predictable.
Here's the idea:
Private Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
Using eFContext As New ApplicationEntities()
Dim requestedTransactionId As Guid = GetAndCheckQueryStringValueGuid("TransactionId")
Dim requestedTransaction As Transaction = Transaction.GetAndConfirm(eFContext, requestedTransactionId)
Dim requestedCustomers As IQueryable(Of Object) =
Customer.GetCustomersForCustomersGrid(eFContext, requestedTransaction)
CustomersGridView.DataSource = requestedCustomers
CustomersGridView.DataBind()
End Sub
I also create a new EF context for each request in Page_Load - I've not found the performance associated with this to be an issue and it makes hunting down problems 10x easier. You may want to consider this, at least to get started. I've seen others in the past suggest putting your context into Session state and fetching it from there when needed, but that feels like it could cause all sorts of hard-to-track-down badness so I've never been bold enough to try and make that work.
As a side note for if you follow my suggestion: if your initial load of the ASPxGridView works but you get errors as you move from page to page, sort columns, etc. then you may need to use some .Includes
for associated entities that display in your grid.
I have since found this example: http://www.asp.net/web-forms/tutorials/continuing-with-ef/using-the-entity-framework-and-the-objectdatasource-control,-part-1-getting-started
which made me realise that my methods on my ReportService
class don't need to be static in order for this to work, which was my main problem in the first place.. I am just not experienced enough with ObjectDataSource
and was following the examples that DevExpress gave from here: http://www.devexpress.com/Support/Center/Example/Details/E2672
So now a new EF ObjectContext
can be created in the scope of the class and then Disposed of when that class is disposed and this seems to work for me.
Like shown below:
public class ReportService : IDisposable
{
private bool disposedValue = false;
private Entities _modelContext = new Entities();
public DataTable GetData(int startRecord, int maxRecords)
{
...
// use _modelContext and process the data
return outputTable;
}
public List<int> GetWeeks()
{
...
// use _modelContext and process the data
}
public int GetPageCount()
{
...
// use _modelContext and process the data
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposedValue)
{
if (disposing)
{
_modelContext.Dispose();
}
}
this.disposedValue = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.