entity framework 静态缓存
entity framework static cache
我正在研究监控应用程序。例如打印机,记录在用户配置文件中。 objective 是获取每台打印机的用户列表。管理员可能需要过滤结果……按用户、个人电脑、默认打印机……并以 CSV 格式导出结果。因此,当管理员进行导出时,csv 需要与活动过滤器相关。我尝试使用 EF 6 创建静态缓存,以保留这些过滤器。
缓存class
public class PrintersCache
{
public static AuditprinterDBEntities1 db = new AuditprinterDBEntities1();
public static IQueryable<AuditPrinter> auditPrinterCache = null;
public static IQueryable<AuditPrinter> AuditPrinterCache
{
get
{
if (auditPrinterCache == null) auditPrinterCache = db.AuditPrinter.Include(a => a.Pc).Include(a => a.PrintersConfig).Include(a => a.Users);
return auditPrinterCache;
}
}
}
在控制器中,我调用 class
static IQueryable<AuditPrinter> auditPrinter = PrintersCache.AuditPrinterCache;
然后,在过滤方法的开头:
auditPrinter = PrintersCache.AuditPrinterCache;
导出方法:
public void ExportCSV()
{
var sw = new StringWriter();
sw.WriteLine(String.Format("{0};{1};{2};{3}", "PcName", "Date", "ActivityName", "UserName"));
foreach (var record in auditPrinter)
{
sw.WriteLine(String.Format("{0};{1};{2};{3}", record.Pc.PcName, record.Date, record.Activity.ActivityName, record.Users.UserName));
}
Response.Clear();
Response.AddHeader("Content-Disposition", "attachment; filename=Export.csv");
Response.ContentType = "text/csv";
Response.Write(sw);
Response.End();
}
它正在运行...但搜索速度有点慢,例如,如果我快速点击搜索按钮 5 或 6 次,我会得到一个 'System.Data.Entity.Core.EntityException'
。 The underlying provider failed on Open.
我需要二级缓存吗?
编辑:搜索过滤方法
public ActionResult LaunchSearch(string keyword, string keyword2, int chx, int pid, int fid)
{
auditPrinter = PrintersCache.AuditPrinterCache;
string returnpartial = "";
switch (chx)
{
case 1:
if(pid!=0)
{
auditPrinter = auditPrinter.Where(a => a.Printers.PrinterId == pid);
}
returnpartial = "Indexprinter";
break;
case 2:
if (pid != 0)
{
auditPrinter = auditPrinter.Where(a => a.UserId == pid);
} else
{
auditPrinter = auditPrinter.OrderBy(a => a.Users.UserName).ThenBy(a => a.Pc.PcName);
}
returnpartial = "Indexvuser";
break;
case 3:
if (pid != 0)
{
auditPrinter = auditPrinter.Where(a => a.Pc.PcId == pid);
}
else
{
auditPrinter = auditPrinter.OrderBy(a => a.Pc.PcName).ThenBy(a => a.Users.UserName);
}
returnpartial = "Indexvpc";
break;
}
if (keyword != "")
{
switch (chx)
{
case 1:
auditPrinter = auditPrinter.Where(a => a.Users.UserName.Contains(keyword)).OrderBy(a => a.Users.UserName).ThenBy(a => a.Pc.PcName);
break;
case 2:
auditPrinter = auditPrinter.Where(a => a.Users.UserName.Contains(keyword)).OrderBy(a => a.Users.UserName).ThenBy(a => a.Pc.PcName);
break;
case 3:
auditPrinter = auditPrinter.Where(a => a.Pc.PcName.Contains(keyword)).OrderBy(a => a.Pc.PcName).ThenBy(a => a.Users.UserName);
break;
}
}
if (keyword2 != "")
{
switch (chx)
{
case 1:
auditPrinter = auditPrinter.Where(a => a.Users.UserName.Contains(keyword) && a.Pc.PcName.Contains(keyword2)).OrderBy(a => a.Pc.PcName).ThenBy(a => a.Users.UserName);
break;
case 2:
auditPrinter = auditPrinter.Where(a => a.Users.UserName.Contains(keyword) && a.Pc.PcName.Contains(keyword2)).OrderBy(a => a.Pc.PcName).ThenBy(a => a.Users.UserName);
break;
case 3:
auditPrinter = auditPrinter.Where(a => a.Pc.PcName.Contains(keyword) && a.Users.UserName.Contains(keyword2)).OrderBy(a => a.Users.UserName).ThenBy(a => a.Pc.PcName);
break;
}
}
if (fid != 0)
{
switch (fid)
{
case 1:
auditPrinter = auditPrinter.Where(a => a.PrintersConfig.IsDefault == true);
break;
case 2:
auditPrinter = auditPrinter.Where(a => a.PrintersConfig.IsDefault == false);
break;
}
}
return PartialView(returnpartial, auditPrinter.ToList());
}
我建议您按如下方式更改 PrinterCache。
public class PrintersCache
{
public static AuditprinterDBEntities1 db = new AuditprinterDBEntities1();
static PrintersCache()
{
AuditPrinterCache = db.AuditPrinter
.Include(a => a.Pc)
.Include(a => a.PrintersConfig)
.Include(a => a.Users);
}
public static IQueryable<AuditPrinter> AuditPrinterCache
{
get; private set;
}
}
这还是没有解决问题,因为你实际上并没有缓存。仅存储一个 linq 查询,当您遍历 foreach (var record in auditPrinter)
.
时,它会被延迟调用
因此这将被多次调用并导致性能问题,以避免通过将其存储到列表中来存储结果。所以 class 应该看起来像
public class PrintersCache
{
public static AuditprinterDBEntities1 db = new AuditprinterDBEntities1();
static PrintersCache()
{
AuditPrinterCache = db.AuditPrinter
.Include(a => a.Pc)
.Include(a => a.PrintersConfig)
.Include(a => a.Users).ToList;
}
public static List<AuditPrinter> AuditPrinterCache
{
get; private set;
}
}
使用内存缓存,你可以这样做:
class PrintersCache
{
private const string CacheName = "MyCacheName";
private const string AuditPrinterKey = "AuditPrinterKey";
private static readonly MemoryCache memoryCache = new MemoryCache(CacheName);
private const int CacheExpirationInMinutes = 20;
public static List<AuditPrinter> GetAuditPrinterCache()
{
// Create a lazy object to retrieve the data when the cache has expired
var newLazyValue = new Lazy<List<AuditPrinter>>(() =>
{
// You should not keep an instance of your db context without disposing it. Also The instantiation of a db context is cheap.
using (var db = new AuditprinterDBEntities1())
{
return db.AuditPrinter
.Include(a => a.Pc)
.Include(a => a.PrintersConfig)
.Include(a => a.Users).ToList();
}
});
// Return the instance of the Lazy object. If the cahce has expired a new instance of the Lazy object is created.
return
((Lazy<List<AuditPrinter>>)
memoryCache.AddOrGetExisting(AuditPrinterKey, newLazyValue, new CacheItemPolicy()
{
// Defines that the cache will expired after 20min
AbsoluteExpiration = new DateTimeOffset(
DateTime.UtcNow.AddMinutes(CacheExpirationInMinutes))
})).Value;
}
}
- 使用内存缓存的
AddOrGetExisting
方法,如果缓存中不存在对象,您将提供某种回退。
- 使用
Lazy<T>
,你只会在缓存为空时调用数据库。
- 使用 AbsoluteExpiration,您可以确保在数据库发生某些更改时更新缓存(在本例中为每 20 分钟一次)。
因为 List<T>
是可查询的,您可以像这样检索数据:
// Initializes your query
var query = PrintersCache.GetAuditPrinterCache().Where(a => a.Printers.PrinterId == pid);
// apply your others conditions here
...
query = query .Where(a => a.Users.UserName.Contains(keyword)).OrderBy(a => a.Users.UserName).ThenBy(a => a.Pc.PcName);
// Return your new filtered list
return query.ToList()
entity framework 上下文不应该是静态的,它的生命周期应该尽可能短。
删除缓存 class 并将上下文创建和查询放入 LaunchSearch
方法中,不要忘记处理此上下文。
只有在存在真正的性能问题时才考虑缓存,缓存复杂对象(如实体)很少是一个好主意。如果您需要缓存,请尝试使用 HTTP 缓存,客户端或服务器端。
public ActionResult LaunchSearch(string keyword, string keyword2, int chx, int pid, int fid)
{
using(var db = new AuditprinterDBEntities1())
{
var auditPrinter = db.AuditPrinter.Include(a => a.Pc).Include(a => a.PrintersConfig).Include(a => a.Users);
// Do whatever you need to do and return result ...
}
}
我正在研究监控应用程序。例如打印机,记录在用户配置文件中。 objective 是获取每台打印机的用户列表。管理员可能需要过滤结果……按用户、个人电脑、默认打印机……并以 CSV 格式导出结果。因此,当管理员进行导出时,csv 需要与活动过滤器相关。我尝试使用 EF 6 创建静态缓存,以保留这些过滤器。
缓存class
public class PrintersCache
{
public static AuditprinterDBEntities1 db = new AuditprinterDBEntities1();
public static IQueryable<AuditPrinter> auditPrinterCache = null;
public static IQueryable<AuditPrinter> AuditPrinterCache
{
get
{
if (auditPrinterCache == null) auditPrinterCache = db.AuditPrinter.Include(a => a.Pc).Include(a => a.PrintersConfig).Include(a => a.Users);
return auditPrinterCache;
}
}
}
在控制器中,我调用 class
static IQueryable<AuditPrinter> auditPrinter = PrintersCache.AuditPrinterCache;
然后,在过滤方法的开头:
auditPrinter = PrintersCache.AuditPrinterCache;
导出方法:
public void ExportCSV()
{
var sw = new StringWriter();
sw.WriteLine(String.Format("{0};{1};{2};{3}", "PcName", "Date", "ActivityName", "UserName"));
foreach (var record in auditPrinter)
{
sw.WriteLine(String.Format("{0};{1};{2};{3}", record.Pc.PcName, record.Date, record.Activity.ActivityName, record.Users.UserName));
}
Response.Clear();
Response.AddHeader("Content-Disposition", "attachment; filename=Export.csv");
Response.ContentType = "text/csv";
Response.Write(sw);
Response.End();
}
它正在运行...但搜索速度有点慢,例如,如果我快速点击搜索按钮 5 或 6 次,我会得到一个 'System.Data.Entity.Core.EntityException'
。 The underlying provider failed on Open.
我需要二级缓存吗?
编辑:搜索过滤方法
public ActionResult LaunchSearch(string keyword, string keyword2, int chx, int pid, int fid)
{
auditPrinter = PrintersCache.AuditPrinterCache;
string returnpartial = "";
switch (chx)
{
case 1:
if(pid!=0)
{
auditPrinter = auditPrinter.Where(a => a.Printers.PrinterId == pid);
}
returnpartial = "Indexprinter";
break;
case 2:
if (pid != 0)
{
auditPrinter = auditPrinter.Where(a => a.UserId == pid);
} else
{
auditPrinter = auditPrinter.OrderBy(a => a.Users.UserName).ThenBy(a => a.Pc.PcName);
}
returnpartial = "Indexvuser";
break;
case 3:
if (pid != 0)
{
auditPrinter = auditPrinter.Where(a => a.Pc.PcId == pid);
}
else
{
auditPrinter = auditPrinter.OrderBy(a => a.Pc.PcName).ThenBy(a => a.Users.UserName);
}
returnpartial = "Indexvpc";
break;
}
if (keyword != "")
{
switch (chx)
{
case 1:
auditPrinter = auditPrinter.Where(a => a.Users.UserName.Contains(keyword)).OrderBy(a => a.Users.UserName).ThenBy(a => a.Pc.PcName);
break;
case 2:
auditPrinter = auditPrinter.Where(a => a.Users.UserName.Contains(keyword)).OrderBy(a => a.Users.UserName).ThenBy(a => a.Pc.PcName);
break;
case 3:
auditPrinter = auditPrinter.Where(a => a.Pc.PcName.Contains(keyword)).OrderBy(a => a.Pc.PcName).ThenBy(a => a.Users.UserName);
break;
}
}
if (keyword2 != "")
{
switch (chx)
{
case 1:
auditPrinter = auditPrinter.Where(a => a.Users.UserName.Contains(keyword) && a.Pc.PcName.Contains(keyword2)).OrderBy(a => a.Pc.PcName).ThenBy(a => a.Users.UserName);
break;
case 2:
auditPrinter = auditPrinter.Where(a => a.Users.UserName.Contains(keyword) && a.Pc.PcName.Contains(keyword2)).OrderBy(a => a.Pc.PcName).ThenBy(a => a.Users.UserName);
break;
case 3:
auditPrinter = auditPrinter.Where(a => a.Pc.PcName.Contains(keyword) && a.Users.UserName.Contains(keyword2)).OrderBy(a => a.Users.UserName).ThenBy(a => a.Pc.PcName);
break;
}
}
if (fid != 0)
{
switch (fid)
{
case 1:
auditPrinter = auditPrinter.Where(a => a.PrintersConfig.IsDefault == true);
break;
case 2:
auditPrinter = auditPrinter.Where(a => a.PrintersConfig.IsDefault == false);
break;
}
}
return PartialView(returnpartial, auditPrinter.ToList());
}
我建议您按如下方式更改 PrinterCache。
public class PrintersCache
{
public static AuditprinterDBEntities1 db = new AuditprinterDBEntities1();
static PrintersCache()
{
AuditPrinterCache = db.AuditPrinter
.Include(a => a.Pc)
.Include(a => a.PrintersConfig)
.Include(a => a.Users);
}
public static IQueryable<AuditPrinter> AuditPrinterCache
{
get; private set;
}
}
这还是没有解决问题,因为你实际上并没有缓存。仅存储一个 linq 查询,当您遍历 foreach (var record in auditPrinter)
.
因此这将被多次调用并导致性能问题,以避免通过将其存储到列表中来存储结果。所以 class 应该看起来像
public class PrintersCache
{
public static AuditprinterDBEntities1 db = new AuditprinterDBEntities1();
static PrintersCache()
{
AuditPrinterCache = db.AuditPrinter
.Include(a => a.Pc)
.Include(a => a.PrintersConfig)
.Include(a => a.Users).ToList;
}
public static List<AuditPrinter> AuditPrinterCache
{
get; private set;
}
}
使用内存缓存,你可以这样做:
class PrintersCache
{
private const string CacheName = "MyCacheName";
private const string AuditPrinterKey = "AuditPrinterKey";
private static readonly MemoryCache memoryCache = new MemoryCache(CacheName);
private const int CacheExpirationInMinutes = 20;
public static List<AuditPrinter> GetAuditPrinterCache()
{
// Create a lazy object to retrieve the data when the cache has expired
var newLazyValue = new Lazy<List<AuditPrinter>>(() =>
{
// You should not keep an instance of your db context without disposing it. Also The instantiation of a db context is cheap.
using (var db = new AuditprinterDBEntities1())
{
return db.AuditPrinter
.Include(a => a.Pc)
.Include(a => a.PrintersConfig)
.Include(a => a.Users).ToList();
}
});
// Return the instance of the Lazy object. If the cahce has expired a new instance of the Lazy object is created.
return
((Lazy<List<AuditPrinter>>)
memoryCache.AddOrGetExisting(AuditPrinterKey, newLazyValue, new CacheItemPolicy()
{
// Defines that the cache will expired after 20min
AbsoluteExpiration = new DateTimeOffset(
DateTime.UtcNow.AddMinutes(CacheExpirationInMinutes))
})).Value;
}
}
- 使用内存缓存的
AddOrGetExisting
方法,如果缓存中不存在对象,您将提供某种回退。 - 使用
Lazy<T>
,你只会在缓存为空时调用数据库。 - 使用 AbsoluteExpiration,您可以确保在数据库发生某些更改时更新缓存(在本例中为每 20 分钟一次)。
因为 List<T>
是可查询的,您可以像这样检索数据:
// Initializes your query
var query = PrintersCache.GetAuditPrinterCache().Where(a => a.Printers.PrinterId == pid);
// apply your others conditions here
...
query = query .Where(a => a.Users.UserName.Contains(keyword)).OrderBy(a => a.Users.UserName).ThenBy(a => a.Pc.PcName);
// Return your new filtered list
return query.ToList()
entity framework 上下文不应该是静态的,它的生命周期应该尽可能短。
删除缓存 class 并将上下文创建和查询放入 LaunchSearch
方法中,不要忘记处理此上下文。
只有在存在真正的性能问题时才考虑缓存,缓存复杂对象(如实体)很少是一个好主意。如果您需要缓存,请尝试使用 HTTP 缓存,客户端或服务器端。
public ActionResult LaunchSearch(string keyword, string keyword2, int chx, int pid, int fid)
{
using(var db = new AuditprinterDBEntities1())
{
var auditPrinter = db.AuditPrinter.Include(a => a.Pc).Include(a => a.PrintersConfig).Include(a => a.Users);
// Do whatever you need to do and return result ...
}
}