5

J'ai été capable de mettre en œuvre une unité de travail un peu sympa pour travailler avec framework d'entité.Mise en œuvre d'UnitOfWork

je suis venu avec ..

public class UnitOfWork : IUnitOfWork 
    { 
     private Database _database; 
     private IDatabaseFactory _databaseFactory; 

     private DbTransaction transaction; 

     public UnitOfWork(IDatabaseFactory databaseFactory) 
     { 
      _databaseFactory = databaseFactory; 
      _database = Database; 

      transaction = _database.Database.Connection.BeginTransaction(); 
     } 

     public Database Database 
     { 
      get { return _database ?? (_database = _databaseFactory.Get()); } 
     } 

     public void Dispose() 
     { 
      try 
      { 
       _database.SaveChanges(); 
       transaction.Commit(); 
      } 
      catch (Exception ex) 
      { 
       transaction.Rollback(); 
      } 
     } 
    } 

Je suis assez sûr que tout le monde est jaloux de cette unité de travail maintenant. (Kidding)

Mais j'ai un petit problème de conception dans cette couche de service.

public class JournalService : IJournalService 
    { 
     IJournalRepository _journalRepository; 

     public JournalService(IJournalRepository journalRepository) 
     { 
      _journalRepository = journalRepository; 
     } 

     public void AjouterJournal(Journal j) 
     { 
      [B]using (IUnitOfWork uow = new UnitOfWork())[/B] 
      { 
       var journal = new Journal(); 
       journalRepository.AddJournal(journal); 

      } 
     } 
    } 

Le problème est que l'unité de travail a besoin d'une injection de base de données, donc je ne peux pas en créer une instance. Je ne peux pas fournir une unité de travail directement dans la couche de service car cela n'aurait aucun sens puisque l'unité de travail doit être jetable. Et comme j'utilise le référentiel pour ajouter mon contenu il n'y a pas besoin d'accéder directement à l'unité de travail, la sauvegarde se fera automatiquement quand elle sera disposée de toute façon.

Je pourrais injecter l'IDatabaseFactory dans ma couche de service mais l'idée est de ne pas l'utiliser là. En fait, la couche de service ne devrait pas savoir à ce sujet.

Que diriez-vous d'une usine UnitOfWork?

Des idées ou des suggestions sur comment je peux résoudre ce problème?

Merci.

+0

Une usine 'UnitOfWork' semble fonctionner. Mais le problème est alors de savoir comment fournir 'IDatabaseFactory' à votre' UnitOfWorkFactory'. – yuxhuang

+0

Injection de DI dans le constructeur? – Rushino

Répondre

7

Vous devez injecter UnitOfWork si vous souhaitez utiliser votre architecture actuelle. Votre service n'aura pas de dépendance interne (cachée) sur l'implémentation de UnitOfWork et il sera mieux testable. Il va de pair avec de nombreux principes de l'architecture orientée objet.

Autre chose est que cette implémentation est seulement utilisable pour de simples opérations CRUD. Dans les services plus complexes, vous obtiendrez la composition de plusieurs opérations (éventuellement à partir de services multiphases) qui fonctionneront chacune avec UnitOfWork. L'appel de plusieurs SaveChanges (et transactions) en une seule opération commerciale n'est probablement pas ce que vous voulez habituellement - dans ce cas, vous ne devez appeler SaveChanges qu'une seule fois à partir d'un service de premier niveau ou de l'appelant du service. Le scénario type est que l'exploitation d'une entreprise unique comporte une unité de travail avec une transaction, mais que vous pouvez effectuer de nombreuses opérations de service dans le cadre de cette opération commerciale.

Une autre implication est la construction de vos référentiels. Ils ont probablement besoin d'accéder à la base de données, n'est-ce pas? Donc vous avez probablement déjà injecté UoW dans le constructeur du référentiel. Si vous faites cela, vous pouvez éviter la relation entre UoW et les services de base du tout.

+0

Pourriez-vous expliquer un peu plus la deuxième partie (sur la mise en œuvre n'est utilisable que pour les simples CRUD ...) J'injecte actuellement les UoW et les Repositories dans ma couche de service. Y-a-t-il un problème avec cela ? Normalement, le démarrage commence lorsque l'opération commerciale est démarrée et se termine après la fin de l'opération commerciale dans le service. Je pourrais finir par appeler d'autres services, mais ces services n'auront de relation avec mon fonctionnement de l'entreprise et ces services ne peuvent être accessibles directement par le contrôleur. Le contrôleur utilisera seulement un service qui est probablement le service dans le contexte réel – Rushino

+0

L'idée derrière la deuxième partie est la composition. Si votre opération commerciale est AddJournal, vous pouvez utiliser Wo et SaveChanges dans l'opération de service.Mais si votre opération commerciale est DoSomethingBig qui consiste en plusieurs appels AddJournal, vous ne voudrez pas appeler SaveChanges et Commit dans chaque appel AddJournal. Vous voudrez l'appeler une seule fois après tous les appels AddJournal. –

+0

Bon point mec je ne savais pas à ce sujet par callig ajouter journal que vous utilisez l'unité de travail qui n'est pas une bonne idée, mais pourquoi appelez-vous addjournal du service si vous pouvez appeler repository.addjournal à la place? Je crois que la classe de service fait plus que des opérations crud. Corrigez-moi si je me trompe n'est pas le travail crud la plupart du temps fait par référentiel? Si jamais je dois ajouter un journal, je n'utiliserai pas la méthode de service. Sinon Où suggérez-vous de mettre en œuvre l'unité de travail? Quel niveau ? – Rushino