我有一个DbContext和许多实体。我想缓存其中的一个实体。即我有一个实体Address
:
public partial class Address : BaseEntity
{
public string Street { get; set; }
public string City { get; set; }
public string ZipPostalCode { get; set; }
public int StateProvinceId { get; set; }
public string ContactName { get; set; }
public string ContactPhone { get; set; }
public string ContactFaxNumber { get; set; }
public string ContactEmail { get; set; }
public virtual StateProvince StateProvince { get; set; }
}
和StateProvince
:
public partial class StateProvince : BaseEntity
{
public string Name { get; set; }
public string Abbreviation { get; set; }
public int TruckSpeedLimit { get; set; }
}
当我通过ID获得地址时,例如:
var address = _db.Addresses.Where(p=>p.Id == id).FirstOrDefault();
,然后尝试获取州名:
var state = address.StateProvince.Name;
它将向数据库再创建一个请求。如果我有一个地址列表,它将创建列表元素附加请求的数量
当然,我可以创建DTO类并在Linq查询中进行投影,例如:
var address = _db.Addresses.Where(p=>p.Id == id).Select(p=> new AddressDTO{ Id = p.Id, ..., StateName = p.StateProvince.Name..}).FirstOrDefault();
但是我的代码架构师根本不喜欢DTO类,而且我也不想为简单实体做重复的类。
状态列表是静态的。我如何对EF说:“请缓存状态!”并避免对数据库的其他请求?
答案 0 :(得分:1)
最好在EF之外执行此操作。只需将静态变量分配给值
db.States.AsNoTracking().ToList()
并且EF中没有机制可以强制其永不刷新实体。
答案 1 :(得分:0)
通常情况下,您将创建自己的缓存机制。
您可以通过定义一些典型的缓存例程的缓存接口开始:
//note: using interface so implementation can be changed later
public interface ICache
{
//store by key, use resolver if not present.
T GetOrAdd(string key, Func<T> resolver);
//invalidate all
void Invalidate();
//invalidate by key
void Invalidate(string key);
}
因此,现在您需要一个实现。根据您的用例,这可能是HttpCache或其他MemoryCache,甚至是哈希表。我把它留给你。
现在,由于是缓存,因此通常使用类似单例的结构来确保只有一个缓存。通常,这由Unity
或AutoFac
之类的IoC容器进行管理。
然后,还可以根据您的其他代码,在查询中使用此缓存。有人喜欢存储库和其他服务。我喜欢Query and Command seperation.
如果已实现,那么使用缓存就很简单了,可以将其应用于您的州。
示例:
var address = _db.Addresses.Where(p=>p.Id == id).FirstOrDefault();
var state = cache.GetOrUpdate($"state-{address.StateProvinceId}",
() =>_db.StateProvinces.FirstOrDefault(c => c.Id == address.StateProvinceId));
但是我必须说; 在分离数据/域层时创建DTO可能会很好。此外;您可以问自己一个没有状态的地址的含义是什么,或者stateId在企业环境中意味着什么。只是说;有很多解决方案,在这里都是有效的。
答案 2 :(得分:0)
如果您可以在没有任何关系的情况下生存,那么这实际上将迫使EF首先查看它已经加载的任何实体,而不是直接转到相关项目的数据库,如果它在本地找不到,那么它将前往服务器。 EF 6 +
context.Set<T>().Find(params object[] keyvalues);