Ответ 1
Я не уверен, что это применимо к NoSQL, но я реализовал шаблон Generic Repository с Raven DB и вот фрагмент.
Сначала я определил несколько интерфейсов
internal interface ISessionProvider : IDisposable
{
IDocumentSession OpenSession();
void CloseSession();
}
public interface IDataAccessManager : IDisposable
{
void Initialize();
void OpenSession();
void CloseSession();
}
public interface IRepository<T> where T : Entity
{
IQueryable<T> Query();
IEnumerable<T> Find(Func<T, bool> exp);
T FirstOrDefault(Func<T, bool> exp);
void Delete(T entity);
void Add(T entity);
void Save();
string PutAttachment(string key, byte[] data);
Attachment GetAttachment(string key);
void DeleteAttachment(string key);
}
И это сокращение реализации
internal class SessionProvider : ISessionProvider
{
...
public IDocumentSession OpenSession()
{
session = store.OpenSession();
return session;
}
public void CloseSession()
{
if (session != null)
{
session.Dispose();
}
}
}
public class DataAccessManager : IDataAccessManager
{
...
public void Initialize()
{
store = new DocumentStore
{
ConnectionStringName = ConnectionString
};
store.Initialize();
store.DatabaseCommands.EnsureDatabaseExists(dbName);
provider = new SessionProvider(store);
}
public void OpenSession()
{
session = provider.OpenSession();
}
public void CloseSession()
{
provider.CloseSession();
}
}
public class Repository<T> : IRepository<T> where T : Entity
{
...
public IEnumerable<T> Find(Func<T, bool> exp)
{
return AsQuaribale().Where(exp);
}
public void Add(T entity)
{
session.Store(entity);
}
public void Save()
{
session.SaveChanges();
}
public string PutAttachment(string key, byte[] data)
{
Guid? etag = null;
var metadata = new RavenJObject
{
{"owner", Thread.CurrentPrincipal.Identity.Name},
{"filename", key}
};
session.Advanced.DatabaseCommands.PutAttachment(key, etag, data, metadata);
return key;
}
public Attachment GetAttachment(string key)
{
return session.Advanced.DatabaseCommands.GetAttachment(key);
}
private IQueryable<T> AsQuaribale()
{
return session.Query<T>().Customize(x => x.WaitForNonStaleResultsAsOfNow(Timeout));
}
}
Пример использования
private void SendData()
{
try
{
dataManager.OpenSession();
repository = new Repository<MyDomainType>();
...
foreach (string path in paths)
{
//read file to memory
byte[] data = File.ReadAllBytes(path);
string fName = Path.GetFileName(path);
myDomainType.Name = fName;
//save data in memory and metadata to the database
string key = repository.PutAttachment(
myDomainType.Id.ToString(), data);
repository.Add(myDomainType);
}
repository.Save();
}
catch (Exception ex)
{
AppManager.LogException(ex);
}
finally
{
dataManager.CloseSession();
dataManager.Dispose();
}
}
Пример теста для создания, который использует метод Find (FirstOrDefault) для assert
[Test]
public void CreateValueTest()
{
var repository = ContainerService.Instance.Resolve<IRepository<DummyType>>();
var expected = new DummyType();
repository.Add(expected);
repository.Save();
DummyType actual = repository.FirstOrDefault(item => item.Id == expected.Id);
Assert.IsTrue(expected == actual);
}