我有一个基本存储库,如下所示:
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;
}
User user = _usersRepository.Get().SingleOrDefault(u => u.Username == "gigi");
这将返回没有Roles属性的用户,这没关系。
User user = _usersRepository.Get(new string[] { "Roles" }).SingleOrDefault(u => u.Username == "gigi");
这将返回用户和Roles属性,这是正常的。
List<User> users = _usersRepository.Get().Where(u => u.Username.StartsWith("gi")).ToList();
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:我分别做了同样的事情:
List<User> users;
using (MyEntities ctx = new MyEntities ())
{
users= ctx.Users.ToList();
}
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;
}
}
}
}
答案 0 :(得分:2)
EF将尝试尽可能多地填充属性。
如果已将数据库行加载到DbContext中,EF将记住该行的DbContext生命周期内的数据。
然后,当您加载引用该行的任何实体时,EF将使用或不使用Include子句填充该属性。
在您的情况下,您正在加载(部分)查询2中的角色表。
运行查询3时,将填充这些行而不包含Include,因为它们已经在DbContext中。
答案 1 :(得分:1)
这条线看起来像是一个单身人士。
EFUnitOfWork currentUnitOfWork = (EFUnitOfWork)UnitOfWork.Current;
如果是,并且您正在使用经典的Singleton模式,您使用静态成员来维护实例,那么您正在使用炸药。您永远不应该使您的数据上下文成为静态。
原因很多。首先,这意味着您的上下文永远不会被破坏,并且将继续消耗内存以进行更改跟踪,直到耗尽内存(或工作进程重新启动)。
第二个也是最大的原因是静态在进程的所有线程之间共享,这意味着多个用户将使用相同的上下文,并且他们很可能会相互踩踏,破坏任何类型的一致性。 / p>
EF数据上下文不是线程安全的,它们也不是并发安全的(它们是两个不同的东西)。
这一行:
UnitOfWork.Current.Dispose();
也很糟糕。除非你非常小心,否则你不应该像这样召唤处理。同样,如果你的上下文是静态的,那么你可以在另一个线程正在使用它时处理它。
总而言之,您的真正问题与在缓存中预先加载数据有关,有时则不然。我建议您认真考虑如何使用UnitOfWork。理想情况下,您将使用依赖注入容器来管理上下文生存期,因此您可以在需要时拥有更一致的上下文状态。