Dựa trên câu trả lời cung cấp bởi Brendan, tôi định nghĩa một kho lưu trữ chung cho trường hợp đặc biệt của danh sách tương đối nhỏ mà ít khi thay đổi, nhưng nặng nề đọc.
1. Giao diện
public interface IRepository<T> : IRepository
where T : class
{
IQueryable<T> AllNoTracking { get; }
IQueryable<T> All { get; }
DbSet<T> GetSet { get; }
T Get(int id);
void Insert(T entity);
void BulkInsert(IEnumerable<T> entities);
void Delete(T entity);
void RemoveRange(IEnumerable<T> range);
void Update(T entity);
}
2. Bình thường/không lưu trữ kho
public class Repository<T> : IRepository<T> where T : class, new()
{
private readonly IEfDbContext _context;
public Repository(IEfDbContext context)
{
_context = context;
}
public IQueryable<T> All => _context.Set<T>().AsQueryable();
public IQueryable<T> AllNoTracking => _context.Set<T>().AsNoTracking();
public IQueryable AllNoTrackingGeneric(Type t)
{
return _context.GetSet(t).AsNoTracking();
}
public DbSet<T> GetSet => _context.Set<T>();
public DbSet GetSetNonGeneric(Type t)
{
return _context.GetSet(t);
}
public IQueryable AllNonGeneric(Type t)
{
return _context.GetSet(t);
}
public T Get(int id)
{
return _context.Set<T>().Find(id);
}
public void Delete(T entity)
{
if (_context.Entry(entity).State == EntityState.Detached)
_context.Set<T>().Attach(entity);
_context.Set<T>().Remove(entity);
}
public void RemoveRange(IEnumerable<T> range)
{
_context.Set<T>().RemoveRange(range);
}
public void Insert(T entity)
{
_context.Set<T>().Add(entity);
}
public void BulkInsert(IEnumerable<T> entities)
{
_context.BulkInsert(entities);
}
public void Update(T entity)
{
_context.Set<T>().Attach(entity);
_context.Entry(entity).State = EntityState.Modified;
}
}
3.Generic cache kho được dựa trên phi lưu trữ một
public interface ICachedRepository<T> where T : class, new()
{
string CacheKey { get; }
void InvalidateCache();
void InsertIntoCache(T item);
}
public class CachedRepository<T> : ICachedRepository<T>, IRepository<T> where T : class, new()
{
private readonly IRepository<T> _modelRepository;
private static readonly object CacheLockObject = new object();
private IList<T> ThreadSafeCacheAccessAction(Action<IList<T>> action = null)
{
// refresh cache if necessary
var list = HttpRuntime.Cache[CacheKey] as IList<T>;
if (list == null)
{
lock (CacheLockObject)
{
list = HttpRuntime.Cache[CacheKey] as IList<T>;
if (list == null)
{
list = _modelRepository.All.ToList();
//TODO: remove hardcoding
HttpRuntime.Cache.Insert(CacheKey, list, null, DateTime.UtcNow.AddMinutes(10), Cache.NoSlidingExpiration);
}
}
}
// execute custom action, if one is required
if (action != null)
{
lock (CacheLockObject)
{
action(list);
}
}
return list;
}
public IList<T> GetCachedItems()
{
IList<T> ret = ThreadSafeCacheAccessAction();
return ret;
}
/// <summary>
/// returns value without using cache, to allow Queryable usage
/// </summary>
public IQueryable<T> All => _modelRepository.All;
public IQueryable<T> AllNoTracking
{
get
{
var cachedItems = GetCachedItems();
return cachedItems.AsQueryable();
}
}
// other methods come here
public void BulkInsert(IEnumerable<T> entities)
{
var enumerable = entities as IList<T> ?? entities.ToList();
_modelRepository.BulkInsert(enumerable);
// also inserting items within the cache
ThreadSafeCacheAccessAction((list) =>
{
foreach (var item in enumerable)
list.Add(item);
});
}
public void Delete(T entity)
{
_modelRepository.Delete(entity);
ThreadSafeCacheAccessAction((list) =>
{
list.Remove(entity);
});
}
}
Sử dụng một khuôn khổ DI (Tôi đang sử dụng Ninject), người ta có thể dễ dàng xác định nếu một kho lưu trữ nên được lưu trữ hay không:
// IRepository<T> should be solved using Repository<T>, by default
kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>));
// IRepository<T> must be solved to Repository<T>, if used in CachedRepository<T>
kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>)).WhenInjectedInto(typeof(CachedRepository<>));
// explicit repositories using caching
var cachedTypes = new List<Type>
{
typeof(ImportingSystem), typeof(ImportingSystemLoadInfo), typeof(Environment)
};
cachedTypes.ForEach(type =>
{
// allow access as normal repository
kernel
.Bind(typeof(IRepository<>).MakeGenericType(type))
.To(typeof(CachedRepository<>).MakeGenericType(type));
// allow access as a cached repository
kernel
.Bind(typeof(ICachedRepository<>).MakeGenericType(type))
.To(typeof(CachedRepository<>).MakeGenericType(type));
});
Vì vậy, , đọc từ kho lưu trữ được lưu trữ xong mà không biết về bộ nhớ đệm. Tuy nhiên, việc thay đổi chúng đòi hỏi phải tiêm từ ICacheRepository<>
và gọi các phương pháp thích hợp.
Làm cách nào tôi có thể thực hiện việc này và giữ cho Vị trí lưu trữ và Dịch vụ bất khả tri? Tôi muốn sử dụng lại R/S cho các ứng dụng không phải web khác. – LaptopHeaven
Hmmm .... Tôi không thấy vấn đề ở đây. Bạn có thể tạo một Kho lưu trữ tiêu chuẩn hoặc một CacheableRepository mà có một sự phụ thuộc ICache (bất cứ điều gì có thể được). Chỉ vì bạn đang "lưu bộ nhớ đệm" không có nghĩa là bạn PHẢI sử dụng httpcache – Will
Bạn có thể triển khai ICache sử dụng bộ nhớ cache ASP.NET (trong đó, btw, có thể được sử dụng trong winforms hoặc bất kỳ ứng dụng nào khác), hoặc sử dụng Bộ nhớ cache của nhóm P & P hoặc việc triển khai bộ nhớ cache của chính bạn. – Will