Sie sollten Expression<Func<T, bool>>
als Vergleichselemente auf Ihrer Schnittstelle verwenden und RepositoryBase
diese Schnittstelle implementieren lassen. Wenn Sie nur verwenden Func
, erhalten Sie keine Übersetzung in L2E usw., sondern müssen die gesamte DB-Tabelle auflisten, bevor Sie die bewerten können Func
. Die Schnittstelle kann simuliert werden, also Unit-Test ohne physische Datenbank und auch mit anderen ORMs.
Es wird im Allgemeinen bevorzugt, die SaveChanges
und DbContext
eine separate IUnitOfWork
Implementierung zu behalten . Sie können den UnitOfWork
an den Repository-Konstruktor übergeben, der auf eine interne Eigenschaft in der UOW zugreifen kann, die den Zugriff auf den Server bereitstellt DbContext
.
Auf diese Weise können Sie dasselbe DbContext
zwischen Repositorys und Stapelaktualisierungen für mehrere Entitätsstammtypen unterschiedlichen Typs freigeben. Sie haben auch weniger offene Verbindungen, was die teuerste Ressource ist, die Sie haben, wenn es um DBs geht.
Nicht zu vergessen, dass sie Transaktionen teilen können. :)
Daher sollten Sie den DbContext nicht im Repository ablegen. Das Repository muss überhaupt nicht verfügbar sein. Aber der UnitOfWork / DbContext muss durch etwas entsorgt werden.
Geben Sie auch das OrderBy
Prädikat auf FindBy
. Da Sie ein zurückgeben IQueryable
und ein Expression
für das Prädikat verwenden, können Sie nach dem Aufruf das Queryable weiterhin erstellen. Zum Beispiel repo.FindBy(it => it.Something == something).OrderBy(it => it.OrderProperty)
. Es wird immer noch in "select [Felder] aus [table] where [prädikat] order by [orderprop]" übersetzt, wenn es aufgelistet wird.
Ansonsten sieht es gut aus.
Hier sind ein paar gute Beispiele:
http://www.martinwilley.com/net/code/data/genericrepository.html
http://www.mattdurrant.com/ef-code-first-with-the-repository-and-unit-of-work-patterns/
Und so mache ich es:
Modell / Common / Geschäftssammlung
Keine Referenzen außer BCL und anderen möglichen Modellen (Schnittstellen / dtos)
public interface IUnitOfWork : IDisposable
{
void Commit();
}
public interface IRepository<T>
{
void Add(T item);
void Remove(T item);
IQueryable<T> Query();
}
// entity classes
Geschäft testet Montage
Verweist nur auf Model / Common / Business Assembly
[TestFixture]
public class BusinessTests
{
private IRepository<Entity> repo;
private ConcreteService service;
[SetUp]
public void SetUp()
{
repo = MockRepository.GenerateStub<IRepository<Entity>>();
service = new ConcreteService(repo);
}
[Test]
public void Service_DoSomething_DoesSomething()
{
var expectedName = "after";
var entity = new Entity { Name = "before" };
var list = new List<Entity> { entity };
repo.Stub(r => r.Query()).Return(list.AsQueryable());
service.DoStuff();
Assert.AreEqual(expectedName, entity.Name);
}
}
Implementierungsassembly für das Entity Framework
Referenzmodell und die Entity Framework / System.Data.Entity-Assemblys
public class EFUnitOfWork : IUnitOfWork
{
private readonly DbContext context;
public EFUnitOfWork(DbContext context)
{
this.context = context;
}
internal DbSet<T> GetDbSet<T>()
where T : class
{
return context.Set<T>();
}
public void Commit()
{
context.SaveChanges();
}
public void Dispose()
{
context.Dispose();
}
}
public class EFRepository<T> : IRepository<T>
where T : class
{
private readonly DbSet<T> dbSet;
public EFRepository(IUnitOfWork unitOfWork)
{
var efUnitOfWork = unitOfWork as EFUnitOfWork;
if (efUnitOfWork == null) throw new Exception("Must be EFUnitOfWork"); // TODO: Typed exception
dbSet = efUnitOfWork.GetDbSet<T>();
}
public void Add(T item)
{
dbSet.Add(item);
}
public void Remove(T item)
{
dbSet.Remove(item);
}
public IQueryable<T> Query()
{
return dbSet;
}
}
Integrierte Testmontage
Referenziert alles
[TestFixture]
[Category("Integrated")]
public class IntegratedTest
{
private EFUnitOfWork uow;
private EFRepository<Entity> repo;
[SetUp]
public void SetUp()
{
Database.SetInitializer(new DropCreateDatabaseAlways<YourContext>());
uow = new EFUnitOfWork(new YourContext());
repo = new EFRepository<Entity>(uow);
}
[TearDown]
public void TearDown()
{
uow.Dispose();
}
[Test]
public void Repository_Add_AddsItem()
{
var expected = new Entity { Name = "Test" };
repo.Add(expected);
uow.Commit();
var actual = repo.Query().FirstOrDefault(e => e.Name == "Test");
Assert.IsNotNull(actual);
}
[Test]
public void Repository_Remove_RemovesItem()
{
var expected = new Entity { Name = "Test" };
repo.Add(expected);
uow.Commit();
repo.Remove(expected);
uow.Commit();
Assert.AreEqual(0, repo.Query().Count());
}
}