我正致力于监控应用程序。例如,打印机,记录在用户配置文件中。目标是获得每个打印机的用户列表。管理员可能必须按用户,按PC,默认打印机...过滤结果...并将结果导出为CSV。因此,当管理员执行导出时,csv需要与活动过滤器相关。我试图用EF 6创建一个静态缓存,以保留这些过滤器。
缓存类
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;
}
}
}
在控制器中,我正在打电话给我的班级
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());
}
答案 0 :(得分:1)
实体框架上下文不应该是静态的,它的生命周期应该尽可能短。
删除缓存类并将上下文创建和查询放在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 ...
}
}
答案 1 :(得分:0)
我建议您按如下方式更改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)
时,这将被调用。
因此,这将被多次调用并导致性能问题,以避免它通过使其列出来存储结果。所以课程应该看起来像
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;
}
}
答案 2 :(得分:0)
使用内存缓存,您可以这样做:
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>
,只有在缓存为空时才会调用数据库。由于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()