缓存一些数据EF

时间:2018-08-27 11:04:29

标签: c# entity-framework caching linq-to-entities

我有一个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说:“请缓存状态!”并避免对数据库的其他请求?

3 个答案:

答案 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,甚至是哈希表。我把它留给你。

现在,由于是缓存,因此通常使用类似单例的结构来确保只有一个缓存。通常,这由UnityAutoFac之类的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);