在ObjectDataSource的静态方法中使用实体框架上下文

时间:2014-05-01 18:55:40

标签: c# entity-framework webforms devexpress objectdatasource

我有一个现有项目,我希望使用ObjectDataSource作为大型数据集,该数据集为DevExpress网格分页结果。

代码示例如下所示。

我在ObjectDataSource所需的静态方法中使用Entity Framework上下文时遇到了问题。

我的问题是我得到了这个例外:

  

System.ObjectDisposedException:ObjectContext实例已经   处置并且不能再用于需要的操作   连接。

有谁知道如何更改以下内容以支持将Entities实例从Page传递给静态方法?

这是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>

这是我的服务类,其中包含静态方法,然后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
        ...
        }
    }

这是网络表单页面背后的代码

    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)
        {
             ...
        }

    }

这是全局代码,其中实体上下文是在请求的开头和结尾设置的。

    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();
            }
        }
    }

2 个答案:

答案 0 :(得分:1)

作为在VB.Net Webforms应用程序中使用DevX网格的人,使用静态/共享方法封装各种数据访问逻辑,另一种方法是跳过在ASPX中创建ObjectDataSource而不是在代码隐藏的Page_Load中设置网格DataSourceID。我创建了这个更易于管理和可预测的内容。

以下是这个想法:

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

我还为Page_Load中的每个请求创建了一个新的EF上下文 - 我没有发现与此相关的性能成为一个问题,它使问题的搜索速度提高了10倍。您可能想要考虑这一点,至少要开始。我在过去看到其他人建议将你的上下文置于Session状态并在需要时从那里获取它,但这感觉它可能会导致各种难以追踪的错误,所以我从来没有大胆尝试并努力工作。

如果您遵循我的建议,请注意:如果ASPxGridView的初始加载有效,但是当您从一个页面移动到另一个页面,排序列等时出现错误,那么您可能需要使用一些{{1} }显示在网格中的关联实体。

答案 1 :(得分:0)

此后我发现了这个例子: http://www.asp.net/web-forms/tutorials/continuing-with-ef/using-the-entity-framework-and-the-objectdatasource-control,-part-1-getting-started

让我意识到我的ReportService课程中的方法不需要静态才能使其正常工作,这首先是我的主要问题。我对ObjectDataSource的经验不足,并且遵循DevExpress从这里提供的示例:http://www.devexpress.com/Support/Center/Example/Details/E2672

所以现在可以在类的范围内创建一个新的EF ObjectContext,然后在处理该类时处理它,这似乎对我有效。

如下所示:

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);
    }

}