2

我有一个看起来像这样的基本存储库:

public class BaseRepository<T> : IBaseRepository<T> where T : class
{
    private DbContext _context;
    private IDbSet<T> _dbSet;

    protected DbContext Context
    {
        get
        {
            if (_context == null)
            {
                EFUnitOfWork currentUnitOfWork = (EFUnitOfWork)UnitOfWork.Current;
                _context = currentUnitOfWork.Context;
            }

            return _context;
        }
    }

    protected IDbSet<T> DbSet
    {
        get
        {
            if (_dbSet == null)
            {
                _dbSet = Context.Set<T>();
            }

            return _dbSet;
        }
    }

    public void Add(T entity)
    {
        DbSet.Add(entity);
    }

    public void Attach(T entity)
    {
        DbSet.Attach(entity);
    }

    public void Delete(T entity)
    {
        DbSet.Remove(entity);
    }

    public void Update(T entity)
    {
        Context.Entry(entity).State = System.Data.EntityState.Modified;
    }             

    public IQueryable<T> Get(string[] includes=null)
    {
        IQueryable<T> set = DbSet;
        if (includes != null)
        {
            foreach (string include in includes)
            {
                set = set.Include(include);
            }
        }
        return set;
    }
  1. User user = _usersRepository.Get().SingleOrDefault(u => u.Username == "gigi"); 这将返回没有 Roles 属性的用户,这没关系。

  2. User user = _usersRepository.Get(new string[] { "Roles" }).SingleOrDefault(u => u.Username == "gigi");这将返回用户和 Roles 属性,这没关系。

  3. List<User> users = _usersRepository.Get().Where(u => u.Username.StartsWith("gi")).ToList();

  4. List<User> users = _usersRepository.Get(new string[] { "Roles" }).Where(u => u.Username.StartsWith("gi")).ToList();

查询 3 和 4 都返回具有 Roles 属性的用户列表。为什么查询 3 返回角色?

LE:这是调用,我在上下文处理后检查用户集合。

            List<User> users = _usersRepository.Get().Where(u => u.Username.StartsWith("gi")).ToList();
            UnitOfWork.Current.Dispose();

LE2:我分别做了同样的事情:

  1.         List<User> users;
            using (MyEntities ctx = new MyEntities ())
            {
                users= ctx.Users.ToList();
            }
    
  2.             List<User> users;
                using (MyEntities ctx = new MyEntities ())
                {
                    users= ctx.Users.Include("Roles").ToList();
                }
    

在第一种情况下,没有加载角色,在第二种情况下,它们是可以的。

我没有看到我在存储库示例中做错了什么。

LE3:这是工作单元

    public class UnitOfWork
    {
        private const string HTTPCONTEXTKEY = "Repository.Key";

        private static IUnitOfWorkFactory _unitOfWorkFactory;
        private static readonly Hashtable _threads = new Hashtable();

        public static IUnitOfWork Current
        {
            get
            {
                IUnitOfWork unitOfWork = GetUnitOfWork();

                if (unitOfWork == null)
                {
                    _unitOfWorkFactory = ObjectFactory.GetInstance<IUnitOfWorkFactory>();
                    unitOfWork = _unitOfWorkFactory.Create();
                    SaveUnitOfWork(unitOfWork);
                }

                return unitOfWork;
            }
        }

        private static IUnitOfWork GetUnitOfWork()
        {
            if (HttpContext.Current != null)
            {
                if (HttpContext.Current.Items.Contains(HTTPCONTEXTKEY))
                {
                    return (IUnitOfWork)HttpContext.Current.Items[HTTPCONTEXTKEY];
                }

                return null;
            }
            else
            {
                Thread thread = Thread.CurrentThread;
                if (string.IsNullOrEmpty(thread.Name))
                {
                    thread.Name = Guid.NewGuid().ToString();
                    return null;
                }
                else
                {
                    lock (_threads.SyncRoot)
                    {
                        return (IUnitOfWork)_threads[Thread.CurrentThread.Name];
                    }
                }
            }
        }

        private static void SaveUnitOfWork(IUnitOfWork unitOfWork)
        {
            if (HttpContext.Current != null)
            {
                HttpContext.Current.Items[HTTPCONTEXTKEY] = unitOfWork;
            }
            else
            {
                lock (_threads.SyncRoot)
                {
                    _threads[Thread.CurrentThread.Name] = unitOfWork;
                }
            }
        }
    }
4

2 回答 2

2

EF 将尝试填充尽可能多的属性。

如果您已将数据库行加载到 DbContext 中,EF 将在 DbContext 的生命周期内记住该行的数据。

然后,当您加载引用该行的任何实体时,EF 将使用或不使用 Include 子句填充该属性。

在您的情况下,您正在加载(一些)查询 2 中的角色表。
当您运行查询 3 时,这些行在没有包含的情况下填充,因为它们已经在 DbContext 中。

于 2012-09-23T21:15:59.053 回答
1

这条线看起来很像单例。

EFUnitOfWork currentUnitOfWork = (EFUnitOfWork)UnitOfWork.Current;

如果是这样,并且您使用的是经典的 Singleton 模式,其中使用静态成员来维护实例,那么您就是在玩炸药。你永远不应该让你的数据上下文成为静态的。

原因很多。首先,这意味着您的上下文永远不会被破坏,并且将继续消耗内存以进行更改跟踪,直到您耗尽内存(或工作进程重新启动)。

第二个也是最大的原因是静态在进程的所有线程之间共享,这意味着多个用户将使用相同的上下文,他们很可能会互相踩踏,破坏任何形式的一致性。

EF 数据上下文不是线程安全的,它们也不是并发安全的(它们是两个不同的东西)。

这一行:

UnitOfWork.Current.Dispose();

也很糟糕。你不应该这样调用 dispose ,除非你非常小心。同样,如果您的上下文是静态的,那么您可以在另一个线程正在使用它时处理它。

总而言之,您的真正问题与将数据预加载到缓存中有关,有时则不然。我建议您认真重新考虑如何使用 UnitOfWork。理想情况下,您将使用依赖注入容器来管理上下文生命周期,因此您可以在需要时拥有更一致的上下文状态。

于 2012-09-23T21:15:51.003 回答