【问题标题】:EntityFramework Context implemented wrong?EntityFramework Context 实现错误?
【发布时间】:2012-03-15 13:47:39
【问题描述】:

我首先为 EF 4.2 代码工作,并且遇到了很多随机上下文连接问题,想知道您是否可以关注一下这个实现,然后为我做错了拍我的手腕(如果它是错误的,那就是)

我已经为这个项目开发了一个存储库模式。

我确定我这样做的方式是问题所在,但无论如何这里是代码:

上下文提供者

public class ContextProvider
{
    private static MyContext context;
    public static MyContext Context
    {
        get
        {
            if (context == null)
            {
                context = new MyContext();
            }

            Database.SetInitializer<MyContext>(null);

            //create the DB if it doesn't exist
            if (!context.Database.Exists())
            {
                context.Database.Create();
                context = new MyContext();
            }

            return context;

        }
    }
 }

这是我的存储库:

public class DataRepository
{
    protected MyContext Context;

    public DataRepository(MyContext context = null)
    {
        Context = context ?? ContextProvider.Context;
    }

    public ProviderBase<Foo> FooProvider { get { return new ProviderBase<Foo>(); } }
    public ProviderBase<Bah> BahProvider { get { return new ProviderBase<Bah>(); } }

}

ProviderBase 类

 public class ProviderBase<T> : IProviderBase<T> where T : BaseClass
    {
        public Boolean UseCaching { get; set; }

        public MyContext Context;

        public ProviderBase(Boolean useCaching = true, MyContext context = null)
        {
            Context = context ?? ContextProvider.Context;
            UseCaching = useCaching;
        }

        #region Implementation of IProviderBase<T>

        protected DbSet<T> DbSet
        {
            get
            {
                return Context.Set<T>();
            }
        }

        ... methods here for CRUD ....

    }

我认为问题在于静态上下文,对吗?如果是,解决办法是什么?

【问题讨论】:

  • @Craig 感谢您展示了如何使用 SO 的搜索功能,但我对此非常了解。我已经阅读了 SO 和其他网站上的数百篇文章,但我对我的问题的解决方案一无所知,因此我发布了这个问题。建设性的回复比简单地发布链接更有帮助......
  • 您正在构建什么类型的应用程序?
  • 它是一个具有 N 层架构的大型网络应用程序

标签: entity-framework c#-4.0 ef-code-first datacontext


【解决方案1】:

Don't use static context.

要修改您的代码,您可以使用:

public class ContextProvider
{
    private const string ContextId = "EF.MyContext"; 

    // Call this only once in Application_Start in Global.asax
    public void InitializeDatabase() 
    {
        MyContext context = GetContext();
        if (!context.Database.Exists())
        {
            context.Database.Create(); 
        }
    }

    public MyContext GetContext()
    {
        MyContext context = HttpContext.Current.Items[ContextId] as MyContext;

        if (context == null)
        {
            context = new MyContext();
            HttpContext.Current.Items[CotnextId] = context; 
        }

        return context;
    }

    // Call this in EndRequest handler in Global.asax
    public void ReleaseContext()
    {
        MyContext context = HttpContext.Current.Items[ContextId] as MyContext;

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

您的存储库将如下所示:

public class DataRepository
{
    protected MyContext Context;

    // If you never need more than one instance of MyContext per repository you
    // can inject context directly and call provider in upper layer
    public DataRepository(ContextProvider provider)
    {
        Context = provider.GetContext();
    }

    public ProviderBase<Foo> FooProvider { get { return new ProviderBase<Foo>(); } }
    public ProviderBase<Bah> BahProvider { get { return new ProviderBase<Bah>(); } }
}

【讨论】:

  • 谢谢,这看起来像我正在寻找的解决方案,我已经实现了,只需要测试一下。感谢您的帮助。
  • 我刚刚对此进行了测试,我收到以下错误:操作无法完成,因为 DbContext 已被释放。我知道这是由于在 Application_EndRequest 中杀死了 dbContext 有什么建议吗?
  • 这意味着你在某个地方设置了上下文。 EndRequest 之后不应使用上下文。
  • 是的,我一定遗漏了一些东西,因为在页面之间的帖子之间插入中断时,最终请求被调用了很多。我现在可能得看看我的查询方法实现了。
  • 每个请求都会调用一次结束请求,但是您的应用程序中的每个操作可以有很多请求,但是每个请求都有自己的上下文,所以这无关紧要。作为调查的解决方法,您还可以将null 分配给Item,表示ReleaseContext 方法中的上下文。在这种情况下,下一个 GetContext 调用将创建新的上下文实例,但您必须找出发生这种情况的原因。
【解决方案2】:

对于单例模式,有非常有用的通用实现 Lazy:

public class ContextProvider 
{ 
    private static Lazy<MyContext> _context = new Lazy<MyContext> context(CreateContext); 

    private static MyContext CreateContext()
    {
            var context = new MyContext(); 

            Database.SetInitializer<MyContext>(null); 

            //create the DB if it doesn't exist 
            if (!context.Database.Exists()) 
            { 
                context.Database.Create(); 
            } 

            return context;
    }

    public static MyContext Context 
    { 
        get { return _context.Value;} 
    } 
 } 

正如其他人已经指出的那样 - 不建议使用静态上下文,而是为每个操作创建\处置它。

【讨论】:

    猜你喜欢
    • 2014-05-23
    • 2016-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多