私は、次のインタフェース/クラスを持っている:リポジトリパターンとローカルキャッシュ
public interface IUnitOfWork : IDisposable
{
event EventHandler<EventArgs> Saved;
DbSet<T> Set<T>() where T : class;
DbEntityEntry<T> Entry<T>(T entity) where T : class;
void Commit();
}
とリポジトリの実装:
public class CachedSqlRepository<T, TKey, TContext> : ICacheRepository<T, TKey, TContext>
where T : class
where TContext : DbContext, IDisposable, new()
{
//A list of the Navigation Properties to include
private readonly Expression<Func<T, object>>[] _NavigationProperties;
public CachedSqlRepository(params Expression<Func<T, object>>[] navigationProperties)
{
_NavigationProperties = navigationProperties;
using (TContext dbContext = new TContext()) //Fetch the List of Entities
{
RefreshCache(dbContext);
}
}
/// <summary>
/// The Collection of Items in the database
/// Note this is a Cache, but should replicate whats in the DB
/// </summary>
public IList<T> Items { get; private set; }
public bool Any(Func<T, bool> predicate)
{
return Items.Any(predicate);
}
public void RefreshCache(DbContext context)
{
switch (_NavigationProperties.Length)
{
case 0:
Items = context.Set<T>().ToList();
break;
case 1:
Items = context.Set<T>().Include(_NavigationProperties[0]).ToList();
break;
//more here
}
}
/// <summary>
/// Refresh the internal cache
/// </summary>
public void RefreshCache()
{
using (TContext dbContext = new TContext())
{
RefreshCache(dbContext);
}
}
public IEnumerable<T> FilterBy(Func<T, bool> predicate)
{
return Items.Where(predicate);
}
public T Add(T entity)
{
T newEntity;
using (TContext dbContext = new TContext())
{
newEntity = dbContext.Set<T>().Add(entity);
if (dbContext.SaveChanges() == 1) //1 change was made
Items.Add(newEntity);
}
return newEntity;
}
public void Delete(TKey id)
{
using (TContext dbContext = new TContext())
{
var attachedEntry = dbContext.Set<T>().Find(id);
if (attachedEntry == null) return; //it doesnt exist anyway!
dbContext.Set<T>().Remove(attachedEntry);
dbContext.SaveChanges();
RefreshCache(dbContext);
}
}
public void Update(T entity, TKey id)
{
if (entity == null) throw new ArgumentException("Cannot update a null entity.");
using (TContext dbContext = new TContext())
{
var entry = dbContext.Entry(entity);
if (entry.State != EntityState.Detached) return;
T attachedEntity = dbContext.Set<T>().Find(id);
if (attachedEntity != null)
{
var attachedEntry = dbContext.Entry(attachedEntity);
attachedEntry.CurrentValues.SetValues(entity);
}
else
{
entry.State = EntityState.Modified; // This should attach entity
}
dbContext.SaveChanges();
RefreshCache(dbContext);
}
}
#region Transaction Methods
public IUnitOfWork StartTransaction()
{
return new EFUnitOfWork(new TContext());
}
public T TransactionAdd(T entity, IUnitOfWork context)
{
context.Saved += OnSave;
return context.Set<T>().Add(entity);
}
public void TransactionDelete(TKey id, IUnitOfWork context)
{
var attachedEntry = context.Set<T>().Find(id);
if (attachedEntry == null) return; //it doesnt exist anyway
context.Saved += OnSave;
context.Set<T>().Remove(attachedEntry);
}
public void TransactionUpdate(T entity, TKey id, IUnitOfWork context)
{
if (entity == null) throw new ArgumentException("Cannot update a null entity.");
var entry = context.Entry(entity);
if (entry.State != EntityState.Detached) return;
T attachedEntity = context.Set<T>().Find(id);
if (attachedEntity != null)
{
var attachedEntry = context.Entry(attachedEntity);
attachedEntry.CurrentValues.SetValues(entity);
}
else
{
entry.State = EntityState.Modified; // This should attach entity
}
context.Saved += OnSave;
}
private void OnSave(object sender, EventArgs e)
{
RefreshCache();
}
#endregion
}
これは、ネット上の様々なパターンから構成されています。私はこれが何十万行ものテーブルに役立つとは思っていませんが、ルックアップテーブルなどのためには、私はいつもDBを打つわけではありません。
これは機能しますが、キャッシュをリフレッシュするなど、いくつかのことはスーパークリーンではありません。すべてのデータを再度取り出す必要がある場合があります(現在進行中の作業)。
このサウンドデザインはありますか?あるいは、私はここでホイールを再発明していますか?
Entity Frameworkは、すでにリポジトリと作業単位パターンを完全に実装しています。この質問への答えを見てください:http://stackoverflow.com/questions/5488313/organizationally-where-should-i-put-common-queries-when-using-entity-framework(この質問にも:http:// stackoverflow.com/questions/5762846/is-unitofwork-and-genericrepository-pattern-redundant-in-ef-4-1-code-first)。彼らが設計しているものには、EFのLinqバインディングを使用します。それらをラップすることは時間の無駄です:IM: –
(もちろんこのアドバイスはキャッシュには言及しませんが、あなたが作成するキャッシュ機構は、貧弱なものの背後に隠すのではなく、既存のEFインターフェースで動作するはずです。 )。 –
ありがとうございました。Merlyn、実際には私たちが元々持っていたCRUDメソッドを汎用化したかったので、本当の意味でリポジトリを使用していません。しかし良いリンク – Simon