I have an identity mapping like so:
Id(x => x.GuidId).Column("GuidId")
.GeneratedBy.GuidComb().UnsavedValue(Guid.Empty);
When I retrieve an object from the database, the GuidId property of my object is Guid.Empty, not the actual Guid (the property in the class is of type System.Guid). However, all of the other properties in the object are populated just fine.
The database field's data type (SQL Server 2005) is uniqueidentifier, and marked as RowGuid.
The application that is connecting to the database is a VB.NET Web Site project (not a "Web Application" or "MVC Web Application" - just a regular "Web Site" project). I open the NHibernate session through a custom HttpModule. Here is the HttpModule:
public class NHibernateModule : System.Web.IHttpModule
{
public static ISessionFactory SessionFactory;
public static ISession Session;
private static FluentConfiguration Configuration;
static NHibernateModule() {
if (Configuration == null) {
string connectionString = cfg.ConfigurationManager.ConnectionStrings["myDatabase"].ConnectionString;
Configuration = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005.ConnectionString(cs => cs.Is(connectionString)))
.ExposeConfiguration(c => c.Properties.Add("current_session_context_class", "web"))
.Mappings(x => x.FluentMappings.AddFromAssemblyOf<LeadMap>().ExportTo("C:\\Mappings"));
}
SessionFactory = Configuration.BuildSessionFactory();
}
public void Init(HttpApplication context) {
context.BeginRequest += delegate {
Session = SessionFactory.OpenSession();
CurrentSessionContext.Bind(Session);
};
context.EndRequest += delegate {
CurrentSessionContext.Unbind(SessionFactory);
};
}
public void Dispose() {
Session.Dispose();
}
}
The strangest part of all, is that from my unit test project, the GuidId property is returned as I would expect. I even rigged it to go for the exact row in the exact database as the web site was hitting. The only differences I can think of between the two projects are
The unit test project is in C#
Something with the way the session is managed between the HttpModule and my unit tests
The configuration for the unit tests is as follows:
Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005.ConnectionString(cs => cs.Is(connectionString)))
.Mappings(x => x.FluentMappings.AddFromAssemblyOf<LeadDetailMap>());
I am fresh out of ideas. Any help would be greatly appreciated.
Thanks
I had a similar problem when in the mapping attribute Name was not set. You can try to save your fluent mappings into Xmls and check them.
Related
This is my first foray into Entity Framework, and I have a working project with EF5 and the repository pattern. I want to do integration testing against a live DB. I made a snapshot of my existing production database and wrote a stored procedure to recreate a fresh snapshot every time I want to run tests. My question is how to I switch my context to this database snapshot when "in unit testing mode"? In my app.config I have both my live and test connection strings as such:
<connectionStrings>
<add name="ReportingDbContext" connectionString="Server=LiveServer;Database=UnifiedReporting;User Id='myuser';Password='mypass';Trusted_Connection=False" providerName="System.Data.SqlClient" />
<add name="TestingDbContext" connectionString="Server=LiveServer;Database=UnifiedReportingSnapshot;User Id='myuser';Password='mypass';Trusted_Connection=False" providerName="System.Data.SqlClient" />
</connectionStrings>
As it stands now, I have my DbContext with the entities I want to use as follows:
public class ReportingDbContext : DbContext
{
public ReportingDbContext() : base("name=ReportingDbContext") // as per my app.config
{
}
// inventory
public DbSet<ComputerEntity> Computers { get; set; }
public DbSet<NetworkAdapterEntity> NetworkAdapters { get; set; }
// ... plus a whole bunch more
}
What I think I need to do is change the base("name=ReportingDbContext") into ("name=TestingDbContext"), but given how I have my Repository/UnitOfWork setup I'm not seeing how I can do so. The issue may be here in my UnitOfWork:
public interface IUnitOfWork : IDisposable
{
void Commit();
// inventory
IRepository<ComputerEntity> Computers { get; }
IRepository<NetworkAdapterEntity> NetworkAdapters { get; }
// ... plus a bunch more
}
public class UnitOfWork : IUnitOfWork
{
private readonly ReportingDbContext _dbContext = null;
public UnitOfWork()
{
_dbContext = new ReportingDbContext();
}
public void Commit()
{
_dbContext.SaveChanges();
}
// Inventory
public IRepository<ComputerEntity> Computers {get { return new Repository<ComputerEntity>(_dbContext); }}
public IRepository<NetworkAdapterEntity> NetworkAdapters { get { return new Repository<NetworkAdapterEntity>(_dbContext); } }
// ... lots more
}
This UnitOfWork has been great is that I can do a bunch of stuff to all my repositories and save it in one shot without having a bunch of contexts floating around to synchronize. It may or may not be relevant to this question, but this is how my UnitOfWork uses the repository. There is only 1 repository class, but it can be fed with any entity type needed:
public interface IRepository<T> where T : class
{
IQueryable<T> GetAll();
IQueryable<T> Find(Expression<Func<T, bool>> predicate);
T GetById(int id);
void Remove(T entity);
void Add(T newEntity);
}
public class Repository<T> : IRepository<T> where T : class
{
protected DbContext DbContext { get; set; }
protected DbSet<T> DbSet { get; set; }
public Repository(DbContext dbContext)
{
if (dbContext == null)
{
throw new ArgumentNullException("dbContext");
}
DbContext = dbContext;
DbSet = DbContext.Set<T>();
}
public IQueryable<T> GetAll()
{
return DbSet;
}
// ... more implementation of the interface, nothing fancy
}
The endpoint of where this magic is used is inside my WCF service. This is where I want to actually run through an integration test. A particular method in my service initializes a unit of work and uses that do stuff. The UnitOfWork creates a ReportingDbContext when it is new'd up, and this ReportingDbContext in turn refers to the connection string of "name=ReportingDbContext". After much reading, I think the answer is to use an IoC container like Unity or Ninject (haven't used one before, but I'd like to), and I'm stuck on how to implement IoC in this situation. Here is an example method that I'm using in my WCF service that seems rather hardcoded to the live database connection string:
public ComputerDTO GetComputerDetails(string hostname, string client)
{
// don't worry about the return type, it's defined elsewhere
using (var uoW = new UnitOfWork())
{
var repo = uoW.Computers;
var computer = repo.Find(x => x.Hostname == hostname && x.CompanyEntity.Name == client).FirstOrDefault();
// do stuff
}
}
I'd like to keep my connection strings inside my app.config if at all possible and be able to somehow switch to the testing connection string during the [SetUp] part of my NUnit testing of the methods in my WCF service.
I alway s use a separate unit test project with an App.config of its own. The connection string has the same name as in the main app but the database connection is different.
When you run unit test, e.g. from within Visual Studio, in the background a unit test runner is executed that is nothing but a regular application with its own configuration, the app.config.
You can start and dispose contexts for each test. Most unit test frameworks have attributes to mark methods as setup/teardown fixtures that can either run per test fixture or per test. You could initialize an IoC container in a test fixture setup ([TestFixtureSetUp] in NUnit) and a context in a test setup ([SetUp] in NUnit).
For some scenarios we use scripts to ensure and restore database state, but for most test we start a TransactionScope in the test setup and dispose it (without committing) in the test teardown. This conveniently rolls back any changes made in the test, but the database changes made in the tests are for real.
I have a ASP.NET MVC4 web api that uses fluent NHibernate, but when I run debug it takes 1½ min to access any site that uses the database the first time I try, so I found Fluent nHibernate Slow Startup Time but I am not sure how to utilize that,
When it runs on the live server it must garbage collect the session data as it takes ages to configure again if I havent used it for a long time.
Is it possiible to cut it down to maybe sub 10 seconds instead of 1.5 minutes?
My current SessionFactory class looks like this
public class SessionFactory
{
private static readonly string ConnString = System.Configuration.ConfigurationManager.ConnectionStrings["MySQLConnectionString"].ConnectionString;
private static ISessionFactory _session;
private static readonly object SyncRoot = new Object();
private static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(MySQLConfiguration
.Standard
.ConnectionString(ConnString))
.Mappings(m => m.FluentMappings
.AddFromAssemblyOf<UserMap>())
.ExposeConfiguration(UpdateSchema)
.BuildSessionFactory();
}
private static void UpdateSchema(Configuration cfg)
{
new SchemaUpdate(cfg).Execute(false, true);
}
public static ISession Session
{
get
{
if (_session == null)
{
lock (SyncRoot)
{
if (_session == null)
_session = CreateSessionFactory();
}
}
return _session.OpenSession();
}
}
}
Here is a screenshot of a dotTrace
Timing the request on my host it takes 1 min and 50 seconds for the initial request, and thats on "live" server (I cant control the IIS there)
I can see a host of things wrong with this code. Your CreateSessionFactory should only ever be called once in the lifetime of your application. Create a static variable in global.asax and call CreateSessionFactory once in Application_Start(). Also in global.asax, you want to setup some events for Application_BeginRequest and Application_EndRequest. This is where you are going to create and destory sessions. This is your unit of work in a web application. You should also store your session in the HttpContext.
public static ISession CurrentSession
{
get { return (ISession)HttpContext.Current.Items[sessionkey]; }
set { HttpContext.Current.Items[sessionkey] = value; }
}
protected void Application_BeginRequest()
{
CurrentSession = SessionFactory.OpenSession();
}
protected void Application_EndRequest()
{
if (CurrentSession != null)
CurrentSession.Dispose();
}
Your code recreates the SessionFactory every time you need a session.
Edit
I would like to try to do what Remo Gloor has recommended
Create a SessionFactoryProvider derived for Provider that retruns a SessionFactory using the code in OnApplicationStarted
Create a binding for SessionFactory using the new provider and put it in SingletonScope
Create a SessionProvider derived from Provider that gets the SessionFactory injected in the constructor and retuns a new session using GetCurrentSession of the factory.
Create a binding for ISession to the above provider with activation and deactivation actions that open, transmit, rollback, and close the session (basiclly the code from Application_BeginRequest, EndRequest). Decalre the binding as in request scope.
Remove Application_BeginRequest, EndRequest.
Bind the repo using Bind().To();
I am looking for a tutorial that hits on these points with a file that I can download and play around with. If it uses lots of generics you needs to be pretty detailed as generics still get me.
Hi
I am trying to do session per request with my nhibernate.
I done this in my global.aspx
using System;
using System.Web.Mvc;
using System.Web.Routing;
using Demo.WebUI.Models.NinjectModules;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate;
using NHibernate.Context;
using Ninject;
using Ninject.Modules;
using Ninject.Web.Mvc;
namespace Demo.WebUI
{
// Note: For instructions on enabling IIS6 or IIS7 classic mode,
// visit http://go.microsoft.com/?LinkId=9394801
public class MvcApplication : NinjectHttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new {controller = "Account", action = "Login", id = UrlParameter.Optional} // Parameter defaults
);
}
public static ISessionFactory SessionFactory { get; private set; }
protected override void OnApplicationStarted()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
SessionFactory = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("test")))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<Demo.Framework.Data.NhibernateMapping.UserMap>())
.ExposeConfiguration(x => x.SetProperty("current_session_context_class", "web"))
.ExposeConfiguration(BuidSchema)
.BuildSessionFactory();
}
protected void Application_BeginRequest(object sender, EventArgs e)
{
ISession session = SessionFactory.OpenSession();
session.BeginTransaction();
CurrentSessionContext.Bind(session);
}
protected void Application_EndRequest(object sender, EventArgs e)
{
ISession session = CurrentSessionContext.Unbind(SessionFactory);
if (session != null)
{
try
{
session.Transaction.Commit();
}
catch (Exception)
{
session.Transaction.Rollback();
}
finally
{
session.Close();
session.Dispose();
}
}
}
protected override IKernel CreateKernel()
{
var modules = new INinjectModule[]
{
new ServiceModule(),
new RepoModule()
};
return new StandardKernel(modules);
}
private static void BuidSchema(NHibernate.Cfg.Configuration config)
{
new NHibernate.Tool.hbm2ddl.SchemaExport(config).Create(false, true);
}
}
}
In my RepoModule I have
Bind<IUserRepo>().To<UserRepo>().WithConstructorArgument("session",MvcApplication.SessionFactory.GetCurrentSession());
This will throw a error because ninject will create the kernal before OnApplicationStarted() gets started and before Application_Begin starts to bind it.
So what should I do?
Edit
This is what I found in some tutorial.
public static ISessionFactory SessionFactory { get; private set; }
public MvcApplication()
{
SessionFactory = CreateSessionFactory();
}
private static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("test")))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<Demo.Framework.Data.NhibernateMapping.UserMap>())
.ExposeConfiguration(x => x.SetProperty("current_session_context_class", "web"))
.ExposeConfiguration(BuidSchema)
.BuildSessionFactory();
}
My binding
Bind<IUserRepo>().To<UserRepo>();
Bind<ISession>().ToMethod(x => MvcApplication.SessionFactory.GetCurrentSession());
So I first create the session factory on constructor load then I bind it to the Isession instead of passing it in as a parameter.
The only thing that I am not sure with the global aspx is if it will keep calling the constructor up everytime and recreating the SessionFactory what is bad. So I am not sure if I need to check if it exists first.
Your implementation is fine but not a good solution as you do manual control of the session lifecycle. The actual way this should be done is to let Ninject decide when the session is created, opened, closed and disposed.
E.g. imagine actions where you don't need any session. Or a larger project where you have several databases and sessions to split the load. In these situations you don't want all the possible sessions be created for each action as this means an avoidable overhead. You rather want that only those are created that are required for the current action.
To do so several changes are required:
Create a SessionFactoryProvider derived for Provider that retruns a SessionFactory using the code in OnApplicationStarted
Create a binding for SessionFactory using the new provider and put it in SingletonScope
Create a SessionProvider derived from Provider that gets the SessionFactory injected in the constructor and retuns a new session using GetCurrentSession of the factory.
Create a binding for ISession to the above provider with activation and deactivation actions that open, transmit, rollback, and close the session (basiclly the code from Application_BeginRequest, EndRequest). Decalre the binding as in request scope.
Remove Application_BeginRequest, EndRequest.
Bind the repo using Bind<IUserRepo>().To<UserRepo>();
I recently blogged about using nhibernate in an asp.net mvc application with a repository pattern. This project provides an example of using nhibernate & ninject. Here are a few links:
http://blog.bobcravens.com/2010/07/using-nhibernate-in-asp-net-mvc/
http://blog.bobcravens.com/2010/06/the-repository-pattern-with-linq-to-fluent-nhibernate-and-mysql/
http://blog.bobcravens.com/2010/09/the-repository-pattern-part-2/
http://blog.bobcravens.com/2010/11/using-ninject-to-manage-critical-resources/
I think that we have a similar architecture. Take a look at the posts and let me know if you have any questions.
BTW, you can download this project at http://gpsnerd.codeplex.com
Bob
Wrap the SessionFactory initialization code in a singleton, that will initialize and configure the sessionfactory once when you access the "Instance" property on it. Use this in BeginRequest instead of current code.
You're using a current session context, you don't have to inject the session!
Inject the SessionFactory instead, then use GetCurrentSession() to obtain an ISession.
After that change, you can use Felice's solution.
At the moment my repository has 2 constructors. When i call these from my mvc website i am alway calling first constructor and thus opening a new session. Should i been passing in the session. How should i be doing this.
public CompanyRepository()
{
_session = NHibernateHelper.OpenSession();
}
public CompanyRepository(ISession session)
{
_session = session;
}
public class NHibernateHelper
{
private static ISessionFactory _sessionFactory;
private static ISessionFactory SessionFactory
{
get
{
if (_sessionFactory == null)
{
var configuration = new Configuration();
configuration.Configure();
configuration.AddAssembly(typeof(UserProfile).Assembly);
configuration.SetProperty(NHibernate.Cfg.Environment.ConnectionStringName,
System.Environment.MachineName);
_sessionFactory = configuration.BuildSessionFactory();
}
return _sessionFactory;
}
}
public static ISession OpenSession()
{
return SessionFactory.OpenSession();
}
}
I'm using the Ninject IOC container ( very new to me ). I have the following container. How would i bind the ISession to the CompanyRepository.
private class EStoreDependencies : NinjectModule
{
public override void Load()
{
Bind<ICompanyRepository>().To<CompanyRepository>();
Bind<IUserProfileRepository>().To<UserProfileRepository>();
Bind<IAddressRepository>().To<AddressRepository>();
Bind<IRolesService>().To<AspNetRoleProviderWrapper>();
Bind<IUserService>().To<AspNetMembershipProviderWrapper>();
Bind<ICurrentUserSerivce>().To<DefaultCurrentUserSerivce>();
Bind<IPasswordService>().To<AspNetMembershipProviderWrapper>();
Bind<IStatusResponseRepository>().To<StatusResponseRepository>();
Bind<ICategoryRepository>().To<CategoryRepository>();
Bind<IProductRepository>().To<ProductRepository>();
}
}
You should be using the "one session per request" pattern, by storing the ISession object in the HttpContext and sharing it between repositories and queries made during the same HTTP request.
Here's an implementation using MVC action attributes.
An easy/basic implementation could also be achieved by simply altering your NHibernateHelper class like this:
public class NHibernateHelper {
//...
const string SessionKey = "NhibernateSessionPerRequest";
public static ISession OpenSession(){
var context = HttpContext.Current;
if(context != null && context.Items.ContainsKey(SessionKey)){
//Return already open ISession
return (ISession)context.Items[SessionKey];
}
else{
//Create new ISession and store in HttpContext
var newSession = SessionFactory.OpenSession();
if(context != null)
context.Items[SessionKey] = newSession;
return newSession;
}
}
}
Code hasn't been neither compiled nor tested... should work however.
Your code or, preferably, dependency injection should always pass the ISession into a repository's constructor. This allows multiple repositories to participate in a single transaction.
I second Paco's recommendation to let a dependency injection framework handle this for you. The challenge with this approach is with non-web applications that do not have clean unit-of-work boundaries like the HTTP request-response cycle. We have repositories that are shared by Windows Forms and ASP.NET applications and we manually manage newing up repositories in the Windows Forms applications.
Use an inversion of control container
Try using sessionFactory.GetCurrentSession() which will allow you to access a contextual session.
This will basically allow you to use the 'session per request' model as described in another answer, without having to code that yourself.
You can even choose what your context is: Http (as your example suggests) or a bunch of others too (I use CallSessionContext for my unit test).
I'm building a asp.net mvc web application. And I'm running quartz in the asp.net context.
I'm using fluent nhibernate for my or mappings.
I'm building a simple job that goes writes an entry in the database.
public void Execute(JobExecutionContext context)
{
ISession session = DataSourceConfiguration.GetSessionFactory().OpenSession();
session.SaveOrUpdate(new JobLogEntry() { Created = DateTime.Now, Message = "Twitter feed read" });
session.Close();
session.Dispose();
}
public static ISessionFactory GetSessionFactory()
{
return Fluently.Configure()
.Database(CurrentDataBaseConfiguration)
.Mappings(m =>
m.AutoMappings.Add(
AutoMap.AssemblyOf<Entry>()
.Where(t => t.Namespace == "QuickBlog.BlogModel.Entities")
))
.BuildSessionFactory();
}
Here is where the error occurs:
public static IPersistenceConfigurer CurrentDataBaseConfiguration
{
get
{
if (_dataBaseConfiguration != null)
return _dataBaseConfiguration;
var config = MsSqlConfiguration.MsSql2005
.ConnectionString(c => c.FromConnectionStringWithKey("QuickBlogDB"))
.UseReflectionOptimizer()
.Cache(c => c.Not
.UseQueryCache())
.ShowSql();
_dataBaseConfiguration = config;
return _dataBaseConfiguration;
}
}
The problem is that c.FromConnectionStringWithKey("QuickBlogDB") is null or empty. How do I get a hold of the configuration info in the quartz.net job?
First of all, you probably should not create your session factory inside your job. I would recommend of having a static class to hold session factory and initialize it in earlier stage, say applications Application_Start method.
It's more resource efficient (a lot) and makes it easier to debug problems as your app won't even start before configuration and preconditions are right.