Alan
Alan

Reputation: 5

C# EF + Repository + UnitOfWorkk pattern

I have a question about architecture , this is my scenario, I am building a layered solution using EF , so I did Repositories for my entities and UnitOfWork to manage my repositories is perfect I put control methods and transaction works , my bussiness entity consumes the unit of work , and I get to work with my business rules , but I have a problem, for example , there is a method I need to use two methods of business to avoid code repetition and work in the same transaction How can I do this ?

Bussiness methods below:

    public void LinkCard(int cardId, long pin) 
    {
        if (cardId < 1 || pin < 1)
            throw new ArgumentException("Invalid parameters!");

        using (UnitOfWorkBol uowb = new UnitOfWorkBol(Log))
        {
            try
            {
                Card card;
                bool success = true;
                Pin pinResult;

                if(!Validator.UseRelesead(cardId, out card, uowb))
                    throw new CardException("La tarjeta no liberado para su uso!");

                pinResult = uowb.RepositoryPin.LoadPinByPin(pin);

                if(!Validator.UseRelesead(pinResult))
                    throw new CardException("La cuenta no está aprobado para su uso!");

                //se não existir cadastra o novo cartão caso contrário só vincula
                if (card == null)
                {
                    card = new Card
                            {
                                CARD_ID = cardId,
                                DISABLED = false,
                                pin = pinResult
                            };

                    success = uowb.GetBaseRepository<Card>().Add(card);
                }
                else 
                { 
                    card.pin = pinResult;
                    success = uowb.RepositoryCard.Update(card);
                }

                if (success)
                    uowb.SaveChanges();

            }
            catch (Exception ex)
            {
                Log.MostraMensagem(LogClass.MsgType.Error, 0, "LinkCard()" + ": " + ex.Message);
                throw;
            }
        }    
    }

    public void CancelCard(int cardId, int reasonId, long Epin) 
    {
        if (cardId < 1)
            throw new ArgumentException("Invalid parameter", "cardId");

        using(UnitOfWorkBol uowb = new UnitOfWorkBol(Log))
        {
            try
            {

                if (Validator.IsCancelled(cardId, uowb))
                    throw new CardException("La tarjeta ya se cancela!");

                Card card = uowb.GetBaseRepository<Card>().LoadById<int>(cardId);

                if (card == null)
                    throw new CardException("Tarjeta no encontrada!");

                //adiciona o cartão na tabela de cancelamento e o desativa
                CancelCard cancel = new CancelCard()
                {
                    card = card,
                    cashier_hist = uowb.RepositoryCashierHist.LoadCurrentCashierHist(Epin),
                    DATE = DateTime.Now,
                    reason_of_cancel = uowb.GetBaseRepository<ReasonOfCancel>().LoadById<int>(reasonId)
                };

                card.DISABLED = true;
                card.pin = null;

                bool success = uowb.GetBaseRepository<CancelCard>().Add(cancel);

                if (success)
                    success = uowb.GetBaseRepository<Card>().Update(card);

                if (success)
                    uowb.SaveChanges();
            }
            catch (Exception ex)
            {
                Log.MostraMensagem(LogClass.MsgType.Error, 0, "CancelCard()" + ": " + ex.Message);
                throw;
            }
        }
    }

i need call these methods in one on the transaction, thanks!

guys, i used transactionScope and works fine, but i dont like this solution because i am opening many transactions the code below:

   public void CancelAndLinkCard(CancelAndTransferDTO dto) 
    {
        using (TransactionScope scope = new TransactionScope()) 
        {
            CancelCard(dto.OldCardId, dto.ReasonId, dto.Epin);
            LinkCard(dto.NewCardId, dto.Pin);
            scope.Complete();
        }
    }

maybe to use a facade pattern and the view access the facade and this to control the transaction is better but i dont know i need help thanks by replies

Upvotes: 0

Views: 113

Answers (3)

Alan
Alan

Reputation: 5

i understand your point of view, so how i said to Gert if you have a good example it would be a good help, maybe these parts of add, delete they should be inside the repository, this way i can reuse.

Upvotes: 0

MarkWalls
MarkWalls

Reputation: 925

If both of these methods are in the same class you could assign the dbContext to a private property and use it instead of creating a new dbContext for each of the methods (And take out your Using statements because otherwise it will dispose of the context when it leaves them).

However, I agree with Gert above - the structure of your solution is what is making this hard for you. DbContext IS a Unit of Work repository and should be treated as such. When we make repositories of repositories it just becomes turtles all the way down and madness comes of that.

Upvotes: 0

Christian Rios
Christian Rios

Reputation: 477

If you are disposing of the context in both methods, I really don't see a way to make it happen. I will probably just write another method that does both things.

Upvotes: 1

Related Questions