Domanda

Qual è l'approccio migliore alla gestione delle transazioni NHibernate utilizzando Autofac all'interno dell'applicazione Web?

Il mio approccio alla sessione è

builder.Register(c => c.Resolve<ISessionFactory>().OpenSession())
       .ContainerScoped();

Per ITransaction , ho ha trovato un esempio su Google Code, ma si basa su HttpContext.Current.Error quando decide se eseguire il rollback.

C'è una soluzione migliore? E quale ambito dovrebbe essere la transazione NHibernate ?

È stato utile?

Soluzione

L'ho pubblicato qualche tempo fa:

http: // .google.com / gruppo / autofac / browse_thread / thread / f10badba5fe0d546 / e64f2e757df94e61 lnk = GST & amp;? q = transazione # e64f2e757df94e61

Modificato, in modo che l'interceptor abbia la capacità di registrazione e l'attributo [Transaction] può anche essere usato su una classe.

[global::System.AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class TransactionAttribute : Attribute
{
}


public class ServicesInterceptor : Castle.Core.Interceptor.IInterceptor
{
    private readonly ISession db;
    private ITransaction transaction = null;

    public ServicesInterceptor(ISession db)
    {
        this.db = db;
    }

    public void Intercept(IInvocation invocation)
    {
        ILog log = LogManager.GetLogger(string.Format("{0}.{1}", invocation.Method.DeclaringType.FullName, invocation.Method.Name));

        bool isTransactional = IsTransactional(invocation.Method);
        bool iAmTheFirst = false;

        if (transaction == null && isTransactional)
        {
            transaction = db.BeginTransaction();
            iAmTheFirst = true;
        }

        try
        {
            invocation.Proceed();

            if (iAmTheFirst)
            {
                iAmTheFirst = false;

                transaction.Commit();
                transaction = null;
            }
        }
        catch (Exception ex)
        {
            if (iAmTheFirst)
            {
                iAmTheFirst = false;

                transaction.Rollback();
                db.Clear();
                transaction = null;
            }

            log.Error(ex);
            throw ex;
        }
    }

    private bool IsTransactional(MethodInfo mi)
    {
        var atrClass = mi.DeclaringType.GetCustomAttributes(false);

        foreach (var a in atrClass)
            if (a is TransactionAttribute)
                return true;

        var atrMethod = mi.GetCustomAttributes(false);

        foreach (var a in atrMethod)
            if (a is TransactionAttribute)
                return true;

        return false;
    }
}

Altri suggerimenti

Quando utilizzo l'autofac uso lo stesso metodo con ambito contenitore ma invece di passare la stessa sessione ai miei oggetti Repository / DAO passo un UnitOfWork con ambito contenitore. L'Unità di lavoro ha questo nel costruttore.

    private readonly ISession _session;
    private ITransaction _transaction;

    public UnitOfWork(ISession session)
    {
        _session = session;
        _transaction = session.BeginTransaction();
    }

E lo smaltimento è:

    public void Dispose()
    {
        try
        {
            if (_transaction != null &&
                            !_transaction.WasCommitted &&
                            !_transaction.WasRolledBack)
                _transaction.Commit();
            _transaction = null;
        }
        catch (Exception)
        {
            Rollback();
            throw;
        }

    }

Sto (ab) usando la roba deterministica di smaltimento in autofac per gestirlo, e in qualche modo mi piace.

L'altra cosa è che sostanzialmente sto prendendo di mira solo un ambiente ASPNet e ho preso la decisione consapevole che una transazione è legata a una richiesta web. Quindi una transazione per modello di richiesta web.

Per questo motivo posso fare questo errore nella gestione del codice in un IHttpModule:

    void context_Error(object sender, System.EventArgs e)
    {
        _containerProvider.RequestContainer.Resolve<IUnitOfWork>().Rollback();
    }

Non ho dato un'occhiata a NHibernate. Soprattutto troppo vicino, ma sono sicuro che c'è qualcosa che fa la maggior parte di questo.

Di solito gestisco personalmente la transazione ..

public ActionResult Edit(Question q){
try {
 using (var t = repo.BeginTransaction()){
  repo.Save(q);
  t.Commit();
  return View();
 }
 catch (Exception e){
  ...
 }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top