C# 在对EF6发出查询之前,始终检查DbSet.Local是安全的
我正在阅读有关使用C# 在对EF6发出查询之前,始终检查DbSet.Local是安全的,c#,entity-framework-6,C#,Entity Framework 6,我正在阅读有关使用实体框架6的缓存和性能的文章,我的想法是总是在向数据库发出任何查询之前检查DbSet.Local集合,如果查询的目的是加载单个实体信息。这就是我提出的模式: pubilc TAccount LoadByUsername<TAccount>(string username) { TAccount acc = null; // Check cache. acc = DbEntitySet.Local.FirstOrDefault(a =>
实体框架6的缓存和性能的文章,我的想法是总是在向数据库发出任何查询之前检查DbSet.Local
集合,如果查询的目的是加载单个实体信息。这就是我提出的模式:
pubilc TAccount LoadByUsername<TAccount>(string username)
{
TAccount acc = null;
// Check cache.
acc = DbEntitySet.Local.FirstOrDefault(a => a.Username.Equals(username, StringComparison.CurrentCultureIgnoreCase));
if (acc == null) {
// Then try and load from db.
return await DbEntitySet.FirstOrDefaultAsync(u => u.Username.Equals(username)).WithCurrentCulture();
}
return acc;
}
即使username
参数是FindById
加载的帐户的用户名,也会导致数据库的4次往返
我的问题是:我是不是发现了什么,还是这种模式不安全?我不确定我是否应该使用这个,因为Identity没有使用任何类似的东西,而且作者显然比我有更多的知识。
DbSet.Local
这样安全吗
--更新
我刚刚发现了一段代码,它可以破解作为参数传递的开放LINQ查询,以检查它是否包含select by id,这样他们就可以在转到db之前检查实体的缓存(通过调用DbSet.Find
)。所以,我想我有点不明白为什么他们没有把这个想法扩展到“FindByEmail”之类的方法上。真是个有趣的问题,我在这方面遇到了一些问题
对于您发布的示例,它看起来很安全。您正在寻找具有已知键值的单个实体。不过,我想你会发现,在不同的情况下,它并不那么安全
例如,我继承了一些代码,其中存储库首先使用本地(缓存)结果,然后在没有结果的情况下返回到向数据库发出查询:
public List<T> LoadAll(Expression<Func<T, bool>> expression)
{
var localResult = _dbSet.Local.AsQueryable().Where(expression).ToList<T>();
return localResult.Count > 0 ? localResult : _dbSet.Where(expression).ToList<T>();
}
public List LoadAll(表达式)
{
var localResult=_dbSet.Local.AsQueryable().Where(expression.ToList();
返回localResult.Count>0?localResult:_dbSet.Where(expression.ToList();
}
这在大多数情况下都很好,但我在发出两个LoadAll请求以获得重叠结果时遇到了一个问题。e、 g.加载图像1和2的图像列表,然后加载图像2和3的图像列表。这两个查询都是使用本地缓存完成的,但第二个查询错误地只包括图像2。映像3尚未在本地缓存中
我要么需要重新编写调用代码以将所有图像预加载到缓存中,要么需要从任何返回列表的方法中删除本地缓存的结果
我看不到一个明显的方法来解决当缓存的查询结果不够好时,发出非缓存的查询
MS发布了一篇文章,其中本地结果直接绑定到UI()。这非常适合您希望能够一次性进行更改并提交所有更改的情况。不太确定它是否能很好地扩展到这一点。为什么这一点被否决了?无论如何,你提出了一个很好的观点。我想,当您需要一组值时,您需要检查是否存在所有预期结果,否则从数据库中加载它们。困难在于知道“预期结果”是什么。最后,我从任何返回列表的内容中删除了缓存结果。试图从一个表达式中计算出期望的结果是什么太难了。。!
public List<T> LoadAll(Expression<Func<T, bool>> expression)
{
var localResult = _dbSet.Local.AsQueryable().Where(expression).ToList<T>();
return localResult.Count > 0 ? localResult : _dbSet.Where(expression).ToList<T>();
}