3
I am working on a C# WPF + EF6 application and find myself lost when it comes to reusing business rules.
I’m using the standard repository + Unit of work, but I believe that copying-pasting complex filters in my calls to the repository seems like a bad idea... So I decided to move the business rules to a new layer, but something still doesn’t feel right... I currently have the following layers:
Viewmodel: Where the logic of interaction with the View and validation occurs
BLL: Layer created to try to work around the above problem, it is responsible for composing the search/addition/removal logic of an entity.
DAL (Repository standard+UOF): Here I only persist POCO in the database.
As I said, something doesn’t smell right... I feel that this approach will bring me future problems, I don’t feel comfortable with it:
mesaBL.TransferirItens(mesaOrigem, mesaDestino, itensIds);
I feel my application is not well structured to change.
Thank you in advance for your attention.
Here a little code:
public class FooViewModel
{
private readonly IContaMesaComandaItemBL _contaMesaComandaItemBL;
public FooViewModel(IContaMesaComandaItemBL contaMesaComandaItemBL)
{
_contaMesaComandaItemBL = contaMesaComandaItemBL;
}
public int ItemId { get; set; }
// Outras propriedades, comandos, métodos, etc...
public void RemoverItemExecute()
{
_contaMesaComandaItemBL
.DeletePorId(ItemId)
.Subscribe(removido =>
{
// Item removido com sucesso
},
ex =>
{
// Erro
});
}
}
public class ContaMesaComandaItemBL : BLBase<ContaMesaComandaItem>, IContaMesaComandaItemBL
{
public ContaMesaComandaItemBL(IUnitOfWorkFactory unitOfWorkFactory) : base(unitOfWorkFactory)
{
}
public IObservable<bool> DeletePorId(int id)
{
return Observable.Create<bool>(obs =>
{
try
{
using (var unitOfWork = UnitOfWorkFactory.Create())
{
var repository = unitOfWork.ContaMesaComandaItemRepository;
repository.Delete(e => e.ComandaItemPizzaMaeId == id);
repository.Delete(e => e.ContaMesaComandaItemId == id);
obs.OnNext(unitOfWork.Save() > 0);
obs.OnCompleted();
}
}
catch (Exception ex)
{
obs.OnError(ex);
}
return Disposable.Empty;
});
}
}
A little more code:
public class ContaMesaBL : BLBase, IContaMesaBL
{
public ContaMesaBL(IUnitOfWorkFactory unitOfWorkFactory) : base(unitOfWorkFactory)
{
}
public IObservable AdicionarComanda(int contaMesaId, ContaMesaComanda comanda)
{
return Observable.Create(obs =>
{
try
{
using (var unitOfWork = UnitOfWorkFactory.Create())
{
var contaMesaRepository = unitOfWork.ContaMesaRepository;
var conta = contaMesaRepository.First(c => c.ContaMesaId == contaMesaId);
conta.DataMovimento = DateTime.Now;
conta.ContaMesaComandas.Add(comanda);
unitOfWork.Save();
obs.OnNext(Unit.Default);
obs.OnCompleted();
}
}
catch(Exception ex)
{
obs.OnError(ex);
}
return Disposable.Empty;
});
}
}
I don’t particularly do BLL ...
– novic
without seeing more of the code is difficult to opine, but layer, component, whatever the strategy, as long as you separate it from the presentation and the bank looks good, it doesn’t necessarily have to be a BLL layer, can be a component... remember that there is no point separating the layers if the model is the same (the class leaves the bank and will stop in the view)
– Ricardo Pontual
@Virgilionovic And how do you deal with business rules? Leave it in Viewmodel/Controller? I have a scenario where I need to work with more than one repository to persist a model. I have a scenario where these business rules will be shared in the future with another module.
– MGM
So it lacks code, it lacks a minimal example, but I practically don’t use BLL is what I don’t think is necessary. but, really without minimum code it is difficult to propose something.
– novic
@Virgilionovic I added an example of code
– MGM
@Ricardopunctual I edited the question and added some code
– MGM
in the projects I worked on that had a BL, it was empty in most cases, the Presentation passed an object to her, and most of the time this passed to DL (Repository, etc.), but it at least separates the Presentation from going directly to DL, now has to see if there are rules of your responsibility there... in your example, the fact of making these two Pins, is a business condition or data model, type FK? If it’s data, you shouldn’t be there...
– Ricardo Pontual
@Ricardopunctual It would be a FK, really that code does not seem to be in the appropriate place... Now I have other scenarios, for example, when entering a Command I need to change the status of the Account and other entities, but I need to ensure that this operation takes place in an atomic way... Would this code be appropriate to be in BLL? Sometimes I wonder if it would be worth having all this work... I added another example code.
– MGM
This second example you mentioned, IMHO makes perfect sense to be in BL and ensure that it is an atomic process (Unitofwork, Transactionscope, etc). If your application has this kind of business logic it makes sense to have a BL or some other layer/Component to separate it, and chiefly ensure that this can be tested separately, this for me is the great advantage of separating the layer, and how your code injects the
IUnitOfWorkFactory
this makes it easy to write a Unit test to ensure that this rule is ok;)– Ricardo Pontual