Unité de travail et cadre de référentiel | Équipe officielle URF, entités traçables et Design Factory
Ce cadre (plus de 100 000 téléchargements au total) minimise la surface de diffusion de votre technologie ORM dans votre application. Ce cadre a été délibérément conçu pour être léger, de petite taille et non intimidant à étendre et à entretenir. Lorsque nous disons léger, nous entendons en réalité léger. Lorsque nous utilisons ce framework avec le fournisseur Entity Framework, il n'y a que 10 classes. Ce framework léger vous permettra de modéliser avec élégance, discrétion et simplicité vos applications et systèmes avec un référentiel, une unité de travail et une conception pilotée par domaine. Utiliser ou non des référentiels génériques ? Le framework permet la liberté des deux référentiels génériques et la possibilité d'ajouter des méthodes de référentiel spécifiques à votre propre domaine, en bref Unité de travail avec des référentiels extensibles et génériques .
Démo en direct : 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 ( ) ; } }
Toutes les méthodes exposées depuis Repository
dans Service
peuvent être remplacées pour ajouter une logique métier/domaine pré ou post. La logique métier du domaine doit se trouver dans la couche Service et non dans les contrôleurs ou les référentiels pour séparer les problèmes.
ICustomerService
, qui doit toujours hériter IService
par exemple IService
CustomerService
qui implémente ICustomerService
container.RegisterType()
, voir l'exemple suivant pour plus de détails sur le câblage de DI et IoC. 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(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 > ( ) ;
}
}