【问题标题】:Entity Framework, Repository Pattern实体框架,存储库模式
【发布时间】:2012-07-14 15:00:31
【问题描述】:

我正在尝试使用实体框架 - 存储库模式。 (Asp.net C#, EF4)

我为每个数据库表创建存储库。但是当我加入表格时,会发生一个错误,说

“指定的 LINQ 表达式包含对与不同上下文关联的查询的引用。”

为了避免错误信息,我把所有的都放在一个类中,像这样:

public class WebOrderRepository
{
    private DbEntities context = new DbEntities(); //Web.config <add name="DBEntities" connectionString=" ...

    public IQueryable<WEBORDERHD> WebOrderHds
    {
        get { return context.WEBORDERHDs; }
    }

    public IQueryable<WEBORDERLN> WebOrderLns
    {
        get { return context.WEBORDERLNs; }
    }
}

您能检查一下我的代码吗?

这是我的存储库类,

public class Repository : IDisposable
{
    protected ShkAdsEntities context;
    private bool _disposed;

    public Repository()
    {
        context = new ShkAdsEntities();
    }

    public void Dispose() //If define this class as Static then, 'Dispose': cannot declare instance members in a static class

    {
        DisposeObject(true);
        GC.SuppressFinalize(this);
    }

    ~Repository()
    {
        DisposeObject(false);
    }

    private void DisposeObject(bool disposing)
    {
        if (_disposed)
        {
        return;
        }

        if(disposing){
        if (context != null)
        {
            context.Dispose();
        }
        _disposed = true;
        }
    }
}

public class WebOrderHdRepository : Repository
{
    public IQueryable<WEBORDERHD> WebOrderHds
    {
        get { return context.WEBORDERHDs; }
    }

    public void Create(WEBORDERHD obj)
    {
    }

    public void Delete(WEBORDERHD ojb)
    {
    }

    public void SubmitChanges()
    {
        context.SaveChanges();
    }
}

public class WebOrderLnRepository : Repository
{
    public IQueryable<WEBORDERLN> WebOrderLns
    {
        get { return context.WEBORDERLNs; }
    }

    public void Create(WEBORDERLN obj)
    {
    }

    public void Delete(WEBORDERLN ojb)
    {
    }

    public void SubmitChanges()
    {
        context.SaveChanges();
    }
}

这是用于测试的控制器,

[HttpGet]
public ActionResult repositoryTest()
{
    WebOrderHdRepository webOrderHdRepository = new WebOrderHdRepository();
    WebOrderLnRepository webOrderLnRepository = new WebOrderLnRepository();

    var result = (from x in webOrderHdRepository.WebOrderHds
          join u in webOrderLnRepository.WebOrderLns on x.OrderNo equals u.OrderNo
          select new {x.OrderNo}).SingleOrDefault();

    return Content(result.OrderNo);
}

我尝试将上下文定义为静态的,

protected static ShkAdsEntities context = null;
public Repository()
{
    if (context == null)
    {
    context = new ShkAdsEntities();
    }
}

然后,发生另一个错误,

Sequence contains more than one element
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: Sequence contains more than one element

Source Error:


Line 116:        {
Line 117:            WebOrderHdRepository webOrderHdRepository = new WebOrderHdRepository();
Line 118:            WebOrderLnRepository webOrderLnRepository = new WebOrderLnRepository();  <== ERROR POINT
Line 119:
Line 120:            var result = (from x in webOrderHdRepository.WebOrderHds

我搜索了很多实体框架存储库模式。但大多数事情都非常复杂。所以我想像上面一样简单。

请指教~

谢谢!

[编辑]

我试试这个,

using(WebOrderHdRepository webOrderHdRepository = new WebOrderHdRepository())
using (WebOrderLnRepository webOrderLnRepository = new WebOrderLnRepository())
{
.
.

但发生错误,

The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.ObjectDisposedException: The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.

Source Error:


Line 114:        {
Line 115:            using(WebOrderHdRepository webOrderHdRepository = new WebOrderHdRepository())
Line 116:            using (WebOrderLnRepository webOrderLnRepository = new WebOrderLnRepository())
Line 117:            {
Line 118:

我认为它尝试处理两次,但我不知道如何修复代码...

谁知道,请指教~

谢谢

【问题讨论】:

    标签: c# asp.net-mvc-3 entity-framework-4 repository-pattern


    【解决方案1】:

    您将能够将异常追溯到此语句:

    var result = (from x in webOrderHdRepository.WebOrderHds
          join u in webOrderLnRepository.WebOrderLns on x.OrderNo equals u.OrderNo
          select new {x.OrderNo}).SingleOrDefault();
    

    错误发生在SingleOrDefault - 您的收藏有多个结果。查看 MSDN 文档以确定是否应该改用 FirstOrDefault

    关于SingleOrDefault 的行为,MSDN 解释说(强调):

    返回序列的唯一元素,如果 序列为空; 如果有更多,此方法将引发异常 序列中的一个元素以上

    关于您的 DbContext,您应该能够拥有单独的存储库,只需确保每个存储库使用相同的上下文对象即可。我猜(没有看到原始实现)每个存储库都实例化了它自己的上下文对象。我没有看到您当前的实现有任何特殊问题,尽管有些人可能会提出类似以下的建议(untested):

      public ActionResult repositoryTest() {
         ActionResult actionRes = default(ActionResult);
    
         using (ShkAdsEntities context = new ShkAdsEntities())
         using (WebOrderHdRepository webOrderHdRepository = new WebOrderHdRepository(context))
         using (WebOrderLnRepository webOrderLnRepository = new WebOrderLnRepository(context)) {
    
            var result = (from x in webOrderHdRepository.WebOrderHds
                          join u in webOrderLnRepository.WebOrderLns on x.OrderNo equals u.OrderNo
                          select new { x.OrderNo }).SingleOrDefault();
    
            actionRes = Content(result.OrderNo);
         }
    
         return actionRes;
      }
    

    更新:
    如果您确实尝试了我在上面演示的存储库测试,则需要进行一些重构。它不适用于您的课程的当前状态。这将是您需要发布的另一个问题。上面的 sn-p 只是您的查询 可能 的一个示例。正如@Florim Maxhuni 所建议的那样,依赖注入(DI)确实是要走的路……仅取决于您的要求和时间限制。如果您的 DbContext 有问题,那将是一个不同的问题,应该在新线程中发布。 :)

    【讨论】:

    • 啊哈!该错误打扰了我的问题的目的:(您认为存储库代码(带有静态变量)还可以吗?我可以在我的项目中使用它吗?
    • 您可以使用受保护的静态而不是将上下文传递给每个存储库,但我不确定处置和重新实例化的含义。如果 using 子句以最里面的 'using' 开头,则将调用所有 Dispose 方法
    • 您应该使用 DI(然后您可以为每个请求创建 DBContext),这样您就不会为每个 Repository DBContext 创建(这会减慢您的网页速度)。
    【解决方案2】:

    每个存储库创建自己的上下文的实施是错误的。相反,必须将上下文注入到存储库中,构造函数注入在这里工作得很好。

    这样您就可以完全控制上下文并在存储库之间共享它。例如,在 Web 应用程序中,您可以拥有一个包含单个请求生命周期的上下文。

    【讨论】:

    • 数据库上下文当然应该在存储库之间共享。在 ASP .NET 应用程序中执行此操作的一种常见方法是每个 HTTP 请求都有一个上下文。它需要创建一个实现 IHttpModule 接口的 http 模块类,在请求的开头初始化上下文并将其存储在 HttpContext.Items 中。在请求结束时,您将处理上下文。 IoC 容器还可以选择初始化具有 HTTP 请求生命周期的对象。
    猜你喜欢
    • 1970-01-01
    • 2010-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多