Кеширую некоторые данные EF - PullRequest
0 голосов
/ 27 августа 2018

У меня есть 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();

, но мой кодArchitect вообще не любит классы DTO, и я также не хочу делать дублирующие классы для простых объектов.

Список состояний статический.Как я могу сказать EF: «Кэшируйте состояния, пожалуйста!»и избежать дополнительных запросов к БД?

Ответы [ 3 ]

0 голосов
/ 27 августа 2018

Лучше всего делать за пределами EF. Просто назначьте статическую переменную значению

db.States.AsNoTracking().ToList()

И в EF нет механизма, который заставлял бы его никогда не обновлять сущности.

0 голосов
/ 27 августа 2018

Если вы можете жить без вытягивания каких-либо отношений, то это фактически заставит EF сначала посмотреть на любые сущности, которые он уже загрузил, вместо того, чтобы идти непосредственно в базу данных для рассматриваемого элемента, если он не найдет один локально, тогда он будет выйти на сервер. EF 6 +

context.Set<T>().Find(params object[] keyvalues);
0 голосов
/ 27 августа 2018

В обычных ситуациях вы бы создали собственный механизм кэширования.

Вы можете начать с определения интерфейса кэширования с некоторыми типичными процедурами кэширования:

//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, такие как Unity или AutoFac.

Затем, в зависимости от вашего другого кода, вы можете использовать этот кеш в своих запросах. Кому-то нравятся репозитории, другие сервисы. Мне нравится Разделение запросов и команд.

Если вы реализовали это, то использование кеша тривиально, и вы можете применить это к своим состояниям.

Пример:

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 в контексте предприятия. Просто сказать; Есть тонны решений, которые могут быть действительными здесь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...