缓存一些数据 EF



我有一个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 说:"请缓存状态!"并避免向 db 发出其他请求?

这最好在 EF 之外完成。 只需为值分配一个静态变量

db.States.AsNoTracking().ToList()

EF 中没有强制它从不刷新实体的机制。

在正常情况下,您将创建自己的缓存机制。

您可以从定义具有一些典型缓存例程的缓存接口开始:

//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,甚至是哈希表。我就交给你了。

现在,由于它是缓存,因此通常使用类似单例的结构,以确保您只有一个缓存。通常,这是由 IoC 容器(如UnityAutoFac(管理的。

然后,根据您的其他代码,您可以在查询中使用此缓存。有些人喜欢存储库,其他服务。我喜欢查询和命令分离。

如果您已经实现了这一点,那么缓存的使用是微不足道的,您可以将其应用于您的状态。

例:

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在企业上下文中意味着什么。只是说;有大量的解决方案在这里都是有效的。

如果你可以在不拉任何关系的情况下生活,那么这实际上会迫使EF首先查看它已经加载的任何实体,而不是直接转到相关项目的数据库,如果它在本地找不到一个,那么它将转到服务器。EF 6+

context.Set<T>().Find(params object[] keyvalues);

最新更新