Il mio team sta aggiornando un progetto legacy. Abbiamo deciso di incorporare il modello di repository insieme a Entity Framework
nel nostro livello di accesso ai dati. Di seguito è riportata una vista di alto livello di questa organizzazione:
IRepository<TEntity>
èun'interfacciagenericautilizzatapereseguireoperazionicomunisuunsetdientità:
publicinterfaceIRepository<TEntity>whereTEntity:class{ObjectSet<TEntity>EntitySet{get;set;}TEntityGet(objectkey);voidInsert(TEntityentity);voidUpdate(TEntityentity);voidSave();}
Adesempio,sehoun'entitàEmployee
,possocrearel'oggettoEmployeeRepository:IRepository<Employee>
.LaclasseDataFactory
vienequindiutilizzatacomeoggettowrapperperoccuparsidiObjectContext
digenerazione,eliminazioneegestionedelleeccezioni:
publicclassDataFactory<TContext,TEntity>:IDisposablewhereTContext:ObjectContext,new()whereTEntity:class{privatebool_disposed=false;privateTContext_context;privateIRepository<TEntity>_repository;publicDataFactory(){_context=newTContext();IRepository<TEntity>repoistory;boolisRepositoryFound=TryGetRepository(outrepoistory);if(!isRepositoryFound){thrownewInvalidOperationException(string.Format("Unable to find repository of type {0}.", typeof(TEntity).FullName));
}
_repository = repoistory;
}
public DataFactory(TContext context, IRepository<TEntity> repository)
{
_context = context;
_repository = repository;
}
public void Do(Action<TContext, IRepository<TEntity>> action)
{
try
{
action(_context, _repository);
}
catch (Exception ex)
{
ProcessException(ex);
}
}
public TResult DoAndReturn<TResult>(Func<TContext, IRepository<TEntity>, TResult> action)
{
try
{
return action(_context, _repository);
}
catch (Exception ex)
{
ProcessException(ex);
return default(TResult);
}
}
private bool TryGetRepository(out IRepository<TEntity> repository)
{
Type repositoryType = Assembly.GetExecutingAssembly().GetTypes().SingleOrDefault(t =>
typeof(IRepository<TEntity>).IsAssignableFrom(t));
if (repositoryType == null)
{
repository = null;
return false;
}
repository = (IRepository<TEntity>)Activator.CreateInstance(repositoryType, _context );
return true;
}
}
Infine, per utilizzare questa classe nel Business Layer, avremmo qualcosa di simile a:
using (var factory = new DataFactory<MyDataContext, Employee>())
{
factory.Do((context, repository) =>
{
// Interact with the repository
});
}
Il mio collega e io abbiamo avuto una lunga conversazione sul fatto che l'oggetto contesto dati debba essere esposto ai livelli sottostanti nei metodi Do()
e DoAndReturn()
. Mentre vedo casi in cui l'accesso diretto al contesto potrebbe essere utile (ad esempio nel caso in cui potremmo voler attivare / disattivare il caricamento lazy per un particolare set di entità), penso che così facendo sconfigge l'intero scopo di astrarre il Livello di accesso ai dati (che si ottiene fornendo un comune IRepository
di contratto) poiché ora gli oggetti possono essere direttamente accessibili / manipolati attraverso ObjectContext
.
Ha suggerito di avere due versioni differenti di questi metodi: uno che espone solo il repository e uno che espone sia il contesto che il repository. È un approccio accettabile? Qualsiasi suggerimento è apprezzato.