Unit-of-Work- und Repository-Framework | Offizielles Team von URF, Trackable Entities und Design Factory
Dieses Framework (mehr als 100.000 Downloads insgesamt) minimiert die Oberfläche, die Ihre ORM-Technologie in Ihrer Anwendung verbreitet. Dieses Framework wurde bewusst so konzipiert, dass es leichtgewichtig und platzsparend ist und sich bei der Erweiterung und Wartung nicht einschüchtern lässt. Wenn wir „Leichtgewicht“ sagen, meinen wir wirklich „Leichtgewicht“, denn wenn dieses Framework mit dem Entity Framework-Anbieter verwendet wird, gibt es nur 10 Klassen. Mit diesem leichten Framework können Sie Ihre Anwendungen und Systeme elegant, unauffällig und einfach mit Repository, Unit of Work und Domain Driven Design strukturieren. Generische Repositories verwenden oder nicht? Das Framework bietet die Freiheit beider, generischer Repositories und die Möglichkeit, Ihrer eigenen Domäne spezifische Repository-Methoden hinzuzufügen, kurz Unit of Work mit erweiterbaren und generischen Repositories .
Live-Demo: longle.azurewebsites.net
public class CustomerController : ODataController
{
private readonly ICustomerService _customerService ;
private readonly IUnitOfWorkAsync _unitOfWorkAsync ;
public CustomerController (
IUnitOfWorkAsync unitOfWorkAsync ,
ICustomerService customerService )
{
_unitOfWorkAsync = unitOfWorkAsync ;
_customerService = customerService ;
}
// GET: odata/Customers
[ HttpGet ]
[ Queryable ]
public IQueryable < Customer > GetCustomer ( )
{
return _customerService . Queryable ( ) ;
}
// GET: odata/Customers(5)
[ Queryable ]
public SingleResult < Customer > GetCustomer ( [ FromODataUri ] string key )
{
return SingleResult . Create ( _customerService . Queryable ( ) . Where ( t => t . CustomerID == key ) ) ;
}
// PUT: odata/Customers(5)
public async Task < IHttpActionResult > Put ( string key , Customer customer )
{
if ( ! ModelState . IsValid )
{
return BadRequest ( ModelState ) ;
}
if ( key != customer . CustomerID )
{
return BadRequest ( ) ;
}
customer . TrackingState = TrackingState . Modified ;
_customerService . Update ( customer ) ;
try
{
await _unitOfWorkAsync . SaveChangesAsync ( ) ;
}
catch ( DbUpdateConcurrencyException )
{
if ( ! CustomerExists ( key ) )
{
return NotFound ( ) ;
}
throw ;
}
return Updated ( customer ) ;
}
// POST: odata/Customers
public async Task < IHttpActionResult > Post ( Customer customer )
{
if ( ! ModelState . IsValid )
{
return BadRequest ( ModelState ) ;
}
customer . TrackingState = TrackingState . Added ;
_customerService . Insert ( customer ) ;
try
{
await _unitOfWorkAsync . SaveChangesAsync ( ) ;
}
catch ( DbUpdateException )
{
if ( CustomerExists ( customer . CustomerID ) )
{
return Conflict ( ) ;
}
throw ;
}
return Created ( customer ) ;
}
//// PATCH: odata/Customers(5)
[ AcceptVerbs ( " PATCH " , " MERGE " ) ]
public async Task < IHttpActionResult > Patch ( [ FromODataUri ] string key , Delta < Customer > patch )
{
if ( ! ModelState . IsValid )
{
return BadRequest ( ModelState ) ;
}
Customer customer = await _customerService . FindAsync ( key ) ;
if ( customer == null )
{
return NotFound ( ) ;
}
patch . Patch ( customer ) ;
customer . TrackingState = TrackingState . Modified ;
try
{
await _unitOfWorkAsync . SaveChangesAsync ( ) ;
}
catch ( DbUpdateConcurrencyException )
{
if ( ! CustomerExists ( key ) )
{
return NotFound ( ) ;
}
throw ;
}
return Updated ( customer ) ;
}
// DELETE: odata/Customers(5)
public async Task < IHttpActionResult > Delete ( string key )
{
Customer customer = await _customerService . FindAsync ( key ) ;
if ( customer == null )
{
return NotFound ( ) ;
}
customer . TrackingState = TrackingState . Deleted ;
_customerService . Delete ( customer ) ;
await _unitOfWorkAsync . SaveChangesAsync ( ) ;
return StatusCode ( HttpStatusCode . NoContent ) ;
}
// GET: odata/Customers(5)/CustomerDemographics
[ Queryable ]
public IQueryable < CustomerDemographic > GetCustomerDemographics ( [ FromODataUri ] string key )
{
return
_customerService . Queryable ( )
. Where ( m => m . CustomerID == key )
. SelectMany ( m => m . CustomerDemographics ) ;
}
// GET: odata/Customers(5)/Orders
[ Queryable ]
public IQueryable < Order > GetOrders ( [ FromODataUri ] string key )
{
return _customerService . Queryable ( ) . Where ( m => m . CustomerID == key ) . SelectMany ( m => m . Orders ) ;
}
protected override void Dispose ( bool disposing )
{
if ( disposing )
{
_unitOfWorkAsync . Dispose ( ) ;
}
base . Dispose ( disposing ) ;
}
private bool CustomerExists ( string key )
{
return _customerService . Query ( e => e . CustomerID == key ) . Select ( ) . Any ( ) ;
}
}
Alle Methoden, die von Repository<TEntity>
in Service<TEntity>
verfügbar gemacht werden, können überschrieben werden, um jegliche Vor- oder Nachdomänen-/Geschäftslogik hinzuzufügen. Zur Trennung von Belangen sollte sich die Domänengeschäftslogik in der Serviceschicht und nicht in Controllern oder Repositorys befinden.
ICustomerService
, die immer IService<TEnttiy>
erben sollte, z. B. IService<Customer>
CustomerService
, das ICustomerService
implementiertcontainer.RegisterType<ICustomerService, CustomerService>()
. Weitere Einzelheiten zur Verkabelung von DI und IoC finden Sie im nächsten Beispiel. public interface ICustomerService : IService < Customer >
{
decimal CustomerOrderTotalByYear ( string customerId , int year ) ;
IEnumerable < Customer > CustomersByCompany ( string companyName ) ;
IEnumerable < CustomerOrder > GetCustomerOrder ( string country ) ;
}
public class CustomerService : Service < Customer > , ICustomerService
{
private readonly IRepositoryAsync < Customer > _repository ;
public CustomerService ( IRepositoryAsync < Customer > repository ) : base ( repository )
{
_repository = repository ;
}
public decimal CustomerOrderTotalByYear ( string customerId , int year )
{
// add any domain logic here
return _repository . GetCustomerOrderTotalByYear ( customerId , year ) ;
}
public IEnumerable < Customer > CustomersByCompany ( string companyName )
{
// add any domain logic here
return _repository . CustomersByCompany ( companyName ) ;
}
public IEnumerable < CustomerOrder > GetCustomerOrder ( string country )
{
// add any domain logic here
return _repository . GetCustomerOrder ( country ) ;
}
public override void Insert ( Customer entity )
{
// e.g. add any business logic here before inserting
base . Insert ( entity ) ;
}
public override void Delete ( object id )
{
// e.g. add business logic here before deleting
base . Delete ( id ) ;
}
}
UnityConfig.cs
public class UnityConfig
{
private static Lazy < IUnityContainer > container = new Lazy < IUnityContainer > ( ( ) =>
{
var container = new UnityContainer ( ) ;
RegisterTypes ( container ) ;
return container ;
} ) ;
public static IUnityContainer GetConfiguredContainer ( )
{
return container . Value ;
}
public static void RegisterTypes ( IUnityContainer container )
{
container
// Register DbContext instead of IDataDataContext, which is now obsolete.
//.RegisterType<IDataContextAsync, NorthwindContext>(new PerRequestLifetimeManager())
. RegisterType < DbContext , NorthwindContext > ( new PerRequestLifetimeManager ( ) )
. RegisterType < IUnitOfWorkAsync , UnitOfWork > ( new PerRequestLifetimeManager ( ) )
. RegisterType < IRepositoryAsync < Customer > , Repository < Customer > > ( )
. RegisterType < IRepositoryAsync < Product > , Repository < Product > > ( )
. RegisterType < IProductService , ProductService > ( )
. RegisterType < ICustomerService , CustomerService > ( )
. RegisterType < INorthwindStoredProcedures , NorthwindContext > ( new PerRequestLifetimeManager ( ) )
. RegisterType < IStoredProcedureService , StoredProcedureService > ( ) ;
}
}