.net - postfix - Necesita un ejemplo simple del uso de nhibernate+unidad de trabajo+patrón de repositorio+capa de servicio+ninject
instalar postfix en debian 9 (1)
estoy usando
- inhibir + inhibir con fluidez
- asp.net mvc 3
- ninject
Actualmente estoy usando nhibernate, ninject con el patrón de repositorio y las capas de servicio.
Asi que tengo esto
ninject
public class NhibernateSessionFactory
{
public ISessionFactory GetSessionFactory()
{
ISessionFactory fluentConfiguration = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("ConnectionString")))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<Framework.Data.Mapping.TableAMap>().Conventions.Add(ForeignKey.EndsWith("Id")))
.ExposeConfiguration(cfg => cfg.SetProperty("adonet.batch_size", "20"))
.ExposeConfiguration(c => c.SetProperty("generate_statistics", "true"))
//.ExposeConfiguration(BuidSchema)
.BuildSessionFactory();
return fluentConfiguration;
}
private static void BuidSchema(NHibernate.Cfg.Configuration config)
{
new NHibernate.Tool.hbm2ddl.SchemaExport(config).Create(false, true);
}
public class NhibernateSessionFactoryProvider : Provider<ISessionFactory>
{
protected override ISessionFactory CreateInstance(IContext context)
{
var sessionFactory = new NhibernateSessionFactory();
return sessionFactory.GetSessionFactory();
}
}
public class NhibernateModule : NinjectModule
{
public override void Load()
{
Bind<ISessionFactory>().ToProvider<NhibernateSessionFactoryProvider>().InSingletonScope();
Bind<ISession>().ToMethod(context => context.Kernel.Get<ISessionFactory>().OpenSession()).InRequestScope()
.OnActivation(StartTransaction)
.OnDeactivation(CommitTransaction);
}
public void CommitTransaction(ISession session)
{
if (session.Transaction.IsActive)
{
session.Transaction.Commit();
}
}
public void StartTransaction(ISession session)
{
if (!session.Transaction.IsActive)
{
session.BeginTransaction();
}
}
}
Así que hago mi fábrica de sesiones nhibernate una vez durante la vida útil de la aplicación, luego la uso, me dan sesiones cuando la necesito.
Un inicio de transacción Comienzo una transacción y al final cierro la transacción.
La razón por la que hice esto fue porque cuando estaba usando el analizador de nhibernate obtendría muchas advertencias sobre el uso de transacciones implícitas. Esto puso una bandaid en el problema, pero nunca lo arreglé (redujo el número, pero todo lo demás cargado de forma perezosa tiene este problema).
un ejemplo de repositorio
public class CalendarRepo : ICalendarRepo
{
private readonly ISession session;
public CalendarRepo(ISession session)
{
this.session = session;
}
public List<CalendarAppointment> RepeatingAppointments(int repeatingId)
{
List<CalendarAppointment> calendarAppointments = session.Query<CalendarAppointment>().Where(x => x.RepeatingId == repeatingId && x.RepeatingId != 0)
.Take(QueryLimits.Appointments)
.ToList();
return calendarAppointments;
}
}
capa de servicio
public class CalendarService : ICalendarService
{
private readonly ICalendarRepo calendarRepo;
public CalendarService(ICalendarRepo calendarRepo)
{
this.calendarRepo = calendarRepo;
}
// normally would return something and take in params
public void SampleServiceMethod()
{
// do some checks if needed
// call up the repository
// call commit
// done.
}
}
Así que eso es básicamente lo que tengo.
Me gustaría usar el patrón de unidad de trabajo para obtener más cosas que me comprometan y hacer las cosas correctamente con las transacciones ( como en este momento me dijeron que no las estoy haciendo bien )
Así que estoy buscando un ejemplo sencillo sobre cómo hacer que todos trabajen juntos y descubrir cuánto necesito cambiar de lo que tengo hasta ahora.
La mayoría de los tutoriales que he visto son más complejos de lo que me gustaría. La mayoría hace TDD y crea repositorios genéricos, lo que es bueno, pero antes de llegar a esa etapa, me gustaría ver un tutorial que haga las cosas simplemente incluso si se está repitiendo el código.
Editar
Así que he estado jugando con esto y se me ocurrió este ejemplo muy simple. No estoy seguro de si lo estoy haciendo bien.
Ninject
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ISessionFactory>().ToProvider<NhibernateSessionFactoryProvider>().InSingletonScope();
kernel.Bind<ISession>().ToMethod(context => context.Kernel.Get<ISessionFactory>().OpenSession()).InRequestScope();
kernel.Bind<ITable1Repo>().To<Table1Repo>();
kernel.Bind<ITable1Service>().To<Table1Service>();
kernel.Bind<IUnitofWork>().To<UnitofWork>();
}
La clase de fábrica nhibernate se muestra en la publicación original.
// Controller
public class Default1Controller : Controller
{
private readonly ITable1Service table1Service;
//
// GET: /Default1/
public Default1Controller(ITable1Service table1Service)
{
this.table1Service = table1Service;
}
public ActionResult Index()
{
table1Service.Save();
return View();
}
}
// dominio
public class Table1
{
public virtual int Id { get; private set; }
public virtual string C1 { get; set; }
public virtual string C2 { get; set; }
}
// Mapeo fluido
public class Table1Mapping : ClassMap<Table1>
{
public Table1Mapping()
{
Id(x => x.Id);
Map(x => x.C1);
Map(x => x.C2);
}
}
// Repo
public class Table1Repo : unitofwork.Models.Repository.ITable1Repo
{
private readonly ISession session;
public Table1Repo(ISession session)
{
this.session = session;
}
public void Create(Table1 tbl1)
{
session.Save(tbl1);
}
}
// capa de servicio
public class Table1Service : unitofwork.Models.Service.ITable1Service
{
private readonly ITable1Repo table1Repo;
private readonly IUnitofWork unitOfWork;
public Table1Service(ITable1Repo table1Repo, IUnitofWork unitOfWork)
{
this.table1Repo = table1Repo;
this.unitOfWork = unitOfWork;
}
public void Save()
{
Table1 a = new Table1();
a.C1 = "test";
a.C2 = "test2";
table1Repo.Create(a);
unitOfWork.Commit();
}
}
// Unidad de trabajo
public class UnitofWork : unitofwork.Models.IUnitofWork
{
private readonly ITransaction transaction;
private readonly ISession session;
public UnitofWork(ISession session)
{
this.session = session;
session.FlushMode = FlushMode.Auto;
transaction = session.BeginTransaction(IsolationLevel.ReadCommitted);
}
public void Commit()
{
if (!transaction.IsActive)
{
throw new InvalidOperationException("Oops! We don''t have an active transaction");
}
transaction.Commit();
}
public void Rollback()
{
if (transaction.IsActive)
{
transaction.Rollback();
}
}
public void Dispose()
{
if (session.IsOpen)
{
session.Close();
}
}
}
Estoy usando ASP.NET ''vanilla'', en lugar de ASP.NET MVC 3, pero esencialmente estamos haciendo lo mismo.
En primer lugar, tengo una clase separada de UnitOfWork
como esta:
public class UnitOfWork
{
private static ISessionFactory SessionFactory
{
get
{
return Container.Get<ISessionFactory>();
}
}
public static ISession Session
{
get
{
return SessionFactory.GetCurrentSession();
}
}
public static void Start()
{
CurrentSessionContext.Bind(SessionFactory.OpenSession());
Session.FlushMode = FlushMode.Commit;
Session.BeginTransaction(IsolationLevel.ReadCommitted);
}
public static void Rollback()
{
Rollback(true);
}
/// <summary>
/// Rollback the current transaction, and optionally start a new transaction
/// </summary>
/// <param name="startNew">Whether to start a new transaction and keep the session open</param>
public static void Rollback(bool startNew)
{
ISession session = CurrentSessionContext.Unbind(SessionFactory);
if (session != null)
{
// Rollback current transaction
if (session.Transaction.IsActive && !session.Transaction.WasRolledBack)
{
session.Transaction.Rollback();
}
// Close and discard the current session
session.Close();
session.Dispose();
session = null;
}
if (startNew)
{
Start();
}
}
/// <summary>
/// Commit the current transaction, keeping the current session open and starting a new transaction
///
/// Call Commit multiple times during a single unit of work if you want to commit database changes in
/// multiple transactions
/// </summary>
public static void Commit()
{
Commit(true);
}
/// <summary>
/// Commit the current transaction, and optionally keep the session open and start a new transaction
///
/// Call Commit multiple times during a single unit of work if you want to commit database changes in
/// multiple transactions
/// </summary>
/// <param name="startNew">Whether to start a new transaction and keep the session open</param>
public static void Commit(bool startNew)
{
if (startNew)
{
Session.Transaction.Commit();
Session.BeginTransaction(IsolationLevel.ReadCommitted);
}
else
{
ISession session = CurrentSessionContext.Unbind(SessionFactory);
if (session != null)
{
if (session.Transaction.IsActive && !session.Transaction.WasRolledBack)
{
session.Transaction.Commit();
}
session.Close();
session.Dispose();
session = null;
}
}
}
}
Utilizo un módulo HTTP para iniciar una nueva unidad de trabajo para cada solicitud web y para confirmar / deshacer automáticamente. No estoy seguro si necesita un módulo HTTP cuando usa ASP.NET MVC 3, o si hay alguna otra forma de hacerlo. De todos modos, las partes relevantes se muestran a continuación:
public class IoCHttpModule : IHttpModule, IDisposable
{
private HttpApplication httpApplication;
public void Init(HttpApplication context)
{
if (context == null)
throw new ArgumentException("context");
this.httpApplication = context;
this.httpApplication.BeginRequest += new EventHandler(BeginRequest);
this.httpApplication.EndRequest += new EventHandler(EndRequest);
this.httpApplication.Error += new EventHandler(Error);
StandardIoCSetup.Initialise(SessionContextType.Web);
}
private void BeginRequest(object sender, EventArgs e)
{
UnitOfWork.Start();
}
private void EndRequest(object sender, EventArgs e)
{
UnitOfWork.Commit(false);
}
private void Error(object sender, EventArgs e)
{
UnitOfWork.Rollback(false);
}
public void Dispose()
{
if (this.httpApplication == null)
return;
this.httpApplication.Dispose();
}
}
Por lo tanto, se inicia una nueva unidad de trabajo para cada solicitud web y se confirma automáticamente si no hay excepciones no controladas. Por supuesto, puede llamar manualmente a UnitOfWork.Commit()
o UnitOfWork.Rollback()
dentro de una solicitud web, si es necesario. La línea StandardIoCSetup.Initialise...
configura NHibernate usando un módulo Ninject, de la misma manera que ya lo está haciendo.
Entonces, en esencia, no es mucho trabajo agregar una unidad de trabajo a lo que ya tiene.