Fluent; SessionSource or SessionFactory for creating sessions? - c#

I'm using NHibernate + Fluent to handle the database in my application. So far I've been using a SessionSource to create my ISession objects. I'm a bit confused now about what comes from NHibernate or Fluent, and what I really should use for creating my sessions.
ISession comes from NHibernate, and the SessionSource from Fluent. I create the SessionSource from a FluentConfiguration, and currently use the SessionSource to create sessions. This is my function to create sessions. The FluentConfiguration and SessionSource is reused:
if (_sessionSource == null)
{
_cfg = Fluently.Configure().Database(SQLiteConfiguration.Standard.ShowSql().UsingFile("test.db"));
_sessionSource = new SessionSource(_cfg.BuildConfiguration().Properties, new MappingsPersistenceModel());
var session = _sessionSource.CreateSession();
_sessionSource.BuildSchema(session);
return session;
}
return _sessionSource.CreateSession();
Does this look reasonable? It sounds more appealing to use a ISessionFactory to create sessions though, so I tried using one. This comes from NHibernate, so I don't know if that's why it is a problem, but it fails when my sessions are created from an ISessionFactory.
// Done once:
_sessionFactory = _cfg.BuildSessionFactory();
// Done each time a session is requested:
_sessionFactory.OpenSession()
Using this I get a MappingException when using the session, saying "No persister for: MyProject.Model.SomeModelClass".
Should I keep using the SessionSource? Or am I missing something regarding the ISessionFactory?

The problem seems to be that the SessionFactory doesn't know about the mappings since they are only given to the SessionSource. Adding the mappings during the fluent configuration and getting the factory from this seems to help. This gave me what looks like a better solution. Does this look reasonable to those of you with more experience on this?
private static ISession CreateSession()
{
if (_sessionFactory == null)
{
_sessionFactory = Fluently.Configure().
Database(SQLiteConfiguration.Standard.ShowSql().UsingFile("test.db")).
Mappings(m => m.FluentMappings.AddFromAssemblyOf<MappingsPersistenceModel>()).
BuildSessionFactory();
}
return _sessionFactory.OpenSession();
}

Please see this class may be help full for you.I have write methods for create factory and session.
public class Common
{
public const string NHibernateSessionKey = "nhibernate.session.key";
public static string ConnString
{
get
{
return System.Configuration.ConfigurationManager.ConnectionStrings["JewelSoftMySqlConn"].ConnectionString;
}
}
public static ISessionFactory FACTORY = CreateFactory();
static ISessionFactory CreateFactory()
{
Configuration config = new Configuration();
IDictionary props = new Hashtable();
props.Add("hibernate.dialect", "NHibernate.Dialect.MySQLDialect");
props.Add("hibernate.connection.provider", "NHibernate.Connection.DriverConnectionProvider");
props.Add("hibernate.connection.driver_class", "NHibernate.Driver.MySqlDataDriver");
props.Add("hibernate.connection.connection_string", Common.ConnString);
config.AddProperties(props);
config.AddInputStream(new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(Resource.Models_hbm)));
return config.BuildSessionFactory();
}
public static ISession GetCurrentSession()
{
ISession currentSession = null;
HttpContext context = HttpContext.Current;
if (context != null)
{
currentSession = context.Items[NHibernateSessionKey] as ISession;
if (currentSession == null)
{
currentSession = FACTORY.OpenSession();
context.Items[NHibernateSessionKey] = currentSession;
}
}
else//will work non web request, like in test environment
currentSession = FACTORY.OpenSession();
return currentSession;
}
}

I know how you feel! The divide between fluent and NH can be rather confusing at the start. In my opinion you should not use SessionSource, AFAIK it is only really useful in testing scenarios. I recomend that you just use the ISessionFactory directly from NH.
Can you post your error? You seem to be using it correctly, so probably there is something wrong with the configuration or the cfg object.

Related

Calling NHibernate ISession.get<T>(object id) twice with the same id returns two different instances

It's my understanding -- e.g. from sources like First and Second Level caching in NHibernate -- that NHibernate's ISession.get<T>(object id) should, when using the "default" setup -- session, etc., return the same instance if called twice with the same id. However, I'm getting two separate instances.
I've seen vaguely-similar questions but no useful results with searches like this, and this.
Here's my get method:
BillingItem IEntityRepository.GetBillingItemByID(int id)
{
var session = Helpers.NHibernateHelper.OpenSession();
using (ITransaction tran = session.BeginTransaction())
{
var ret = session.Get<BillingItem>(id);
tran.Commit();
return ret;
}
}
Here's my test, which is failing:
var repo = (IEntityRepository) new SqliteEntityRepository();
var bi1 = repo.GetBillingItemByID(26);
var bi2 = repo.GetBillingItemByID(26);
Assert.AreSame(bi1, bi2); // fails
Here's NHibernateHelper just in case you want to see it:
internal static class NHibernateHelper
{
private static ISessionFactory _sessionFactory;
internal static ISession OpenSession()
{
return SessionFactory.OpenSession();
}
private static ISessionFactory SessionFactory
{
get
{
if (_sessionFactory == null)
{
var configuration = new Configuration();
configuration.Configure();
configuration.AddAssembly(typeof(BillingItem).Assembly);
configuration.AddAssembly(typeof(PaymentItem).Assembly);
var mapper = new ModelMapper();
mapper.AddMappings(typeof(Mappings.BillingItemMapping).Assembly.GetExportedTypes());
mapper.AddMappings(typeof(Mappings.PaymentItemMapping).Assembly.GetExportedTypes());
var mapping = mapper.CompileMappingForAllExplicitlyAddedEntities();
configuration.AddDeserializedMapping(mapping, null);
SchemaMetadataUpdater.QuoteTableAndColumns(configuration);
_sessionFactory = configuration.BuildSessionFactory();
}
return _sessionFactory;
}
}
}
What am I missing here?
This must be true, because in a snippet above we are using ... almost anti-pattern ... a very short session:
using (ISession session = Helpers.NHibernateHelper.OpenSession())
{ ... }
That is not what we usually need. We need a Unit of Work session. In web app, it usually last through whole request... (In a desktop... there should be some UoW workaround).
So, if there are two different sessions - then both produce different run-time instance.
Repositories should not be responsible for handling transactions. You need to have a single instance of unit of work that would allow you to run multiple queries in the same session/transaction.
It looks to me that the OpenSession() method creates a new session each time. Can you post the code for it?

Create Connection Strings with the Factory Pattern

I have the following code
public static DatabaseFactory {
public DatabaseProvider Create(dataSource, ProviderType provider type){
//dataSource = "Server\Instance", "MyOracleDB"
if (type == ProviderType.Sql)
return new SqlDatabaseProvider("$data source = {dataSource}; integrated security = True; MultipleActiveResultSets = True;");
throw new NotImplementedException("Provider not found");
}
}
Doing it this way I have to hard code a connection string for each provider I implement. I'm wondering if there is a dynamic way to retrieve a connection string or build it based on a value.
The purpose of a factory is to abstract the creation of an object so that the calling code doesn't need to be aware of the specifics, and that you may perform addition operations after construction, and that you may return a subclass of the factory's return type.
So it might be more typical that your calling code is not even aware of the database type. Your code may look more like this:
var mainProvider = DatabaseFactory.Create("main");
var backupProvider = DatabaseFactory.Create("backup");
Then your factory might look like this:
public static DatabaseFactory
{
public static DatabaseProvider Create(string key)
{
var providerType = GetProviderTypeFromConfig(key);
var connectionString = GetConnectionFromConfig(key);
if (providerType == ProviderType.Sql)
return new SqlDatabaseProvider(connectionString);
if (providerType == ProviderType.Oracle)
return new OracleDatabaseProvider(connectionString);
throw new NotImplementedException("Provider not found");
}
}
Now you would need to write the code for GetProviderTypeFromConfig and GetConnectionFromConfig which would go off to some XML/JSON file, or even spin up a DB connection itself, to get the actual values used.
This type of code then becomes easier to test too as each part can be unit tested.

Application design: NH-session management, generic repository, ASP.NET MVC

Having defined a domain model I want to figure out how to do the rest of work.
DATA ACCESS LAYER
I had read before that it is not necessary to code own UnitOfWork implementation over ISession (thogh I found a much information on how to do it pretty well). So I'm quite confused.. I have repository interface like this:
public interface IRepository<T> where T: AbstractEntity<T>, IAggregateRoot
{
T Get(Guid id);
IQueryable<T> Get(Expression<Func<T, Boolean>> predicate);
IQueryable<T> Get();
T Load(Guid id);
void Add(T entity);
void Remove(T entity);
void Remove(Guid id);
void Update(T entity);
void Update(Guid id);
}
Where in the concrete implementation there are two options:
OPTION A
Is to inject ISessionFactory thru constructor and have something similar to:
public class Repository<T> : IRepository<T> where T : AbstractEntity<T>, IAggregateRoot
{
private ISessionFactory sessionFactory;
public Repository(ISessionFactory sessionFactory)
{
this.sessionFactory = sessionFactory;
}
public T Get(Guid id)
{
using(var session = sessionFactory.OpenSession())
{
return session.Get<T>(id);
}
}
}
OPTION B
Is to use NHibernateHelper class
using(var session = NHibernateHelper.GetCurrentSession())
{
return session.Get<T>(id);
}
Where NHibernateHelper is
internal sealed class NHibernateHelper
{
private const string CurrentSessionKey = "nhibernate.current_session";
private static readonly ISessionFactory sessionFactory;
static NHibernateHelper()
{
sessionFactory = new Configuration().Configure().BuildSessionFactory();
}
public static ISession GetCurrentSession()
{
HttpContext context = HttpContext.Current;
ISession currentSession = context.Items[CurrentSessionKey] as ISession;
if(currentSession == null)
{
currentSession = sessionFactory.OpenSession();
context.Items[CurrentSessionKey] = currentSession;
}
return currentSession;
}
public static void CloseSession()
{
HttpContext context = HttpContext.Current;
ISession currentSession = context.Items[CurrentSessionKey] as ISession;
if(currentSession == null)
{
return;
}
currentSession.Close();
context.Items.Remove(CurrentSessionKey);
}
public static void CloseSessionFactory()
{
if(sessionFactory != null)
{
sessionFactory.Close();
}
}
}
What's option is prefered?
Why(besides the injection)?
If I use option A where do I place configuration of ISessionFactory?
Should it be placed somewhere in ASP.NET MVC project? How?
Thank you for reading the monster-question! Your guidance is appreciated!
How to handle injecting dependencies with mvc is somewhat version specific but it always helps to use a real Dependency Injection (DI) container. However you slice it, this solution will need you to Inject an ISession into the Repository rather than an ISessionFactory. This allows your DI container to manage the lifetime of the session properly.
Assuming you're using Asp.Net MVC 3 and dont have an attachment to a specific DI container already, fire up your Nuget console and type:
install-package Ninject.MVC3
This will go, download Ninject (which is a DI container) and configure your mvc application to use it. It will also create a file ~/App_Start/NinjectMVC3.cs which is where you'll configure your dependencies as such.
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ISessionFactory>()
.ToMethod(c => new Configuration().Configure().BuildSessionFactory())
.InSingletonScope();
kernel.Bind<ISession>()
.ToMethod((ctx) => ctx.Kernel.Get<ISessionFactory>().OpenSession())
.InRequestScope();
kernel.Bind<IRepository<>>().To<Repository<>>();
}
The first statement tells ninject that when something requires an ISessionFactory, it should lazily initialize NHibernate and create one. This session factory is then to be held as an application-wide singleton for the lifetime of the application.
The second statement tells ninject that when something requires an ISession, it should get an instance of ISessionFactory and call OpenSession(). This Session is then reused within the scope of the request and destroyed at the end of the request.
The third statement tells ninject that when something requires an IRepository of any type, it should just new one up using it's built in logic to resolve dependencies.
From here you can write your code as follows and everything should just work.
public class WidgetController : Controller
{
private readonly IRepository<Widget> _repository;
public WidgetController(IRepository<Widget> repository)
{
_repository = repository;
}
}
With regards to the Repository I'd like to point you to an excelent blog post Repository is the new Singleton
I usually use a read only property, on my repository, like this
protected ISession Session
{
get
{
return NHibernateSessionFactory.CurrentFor(dataBaseFactoryKey);
}
}
My NHibernateSessionFactory works like this.
In web apps you should use pattern NH session per web request. I think you should have only one session per web request and your repositories should use this single session.
To implement this you need to write IHttpModule which will open session, begin transaction and bind session as ambient (current) session when request begins and end transaction and close session when request ends. You also need to set current_session_context_class to "web". Then your Repository/DAO will look like this
public TEntity Get(object id)
{
return sessionFactory.GetCurrentSession().Get<TEntity>(id);
}
Best pattern with MVC and NHibernate is session per request.
steps:
In Global.asax add
public static ISessionFactory SessionFactory;
In Application_Start() configure and build session factory:
var config = new Configuration().Configure();
SessionFactory = config.BuildSessionFactory();
In Application_BeginRequest open the session and bind it to
CurrentSessionContext:
var nhSession = SessionFactory.OpenSession();
CurrentSessionContext.Bind(Session);
In Application_EndRequest() unbind and dispose the session
Now in your controller you can access your session invoking:
Global.SessionFactory.GetCurrentSession();
EDIT: Following #hival comment
Inside your controller handle your model in a using block and perform commit/rollback based on your logic.

NHibernate SessionFactory Thread safe Issue

So here is the problem. I have a common class library that holds all the repositories, domain and mapping files so the library can be reused within other web beased applications. Now within this class library there is a peiece of code that allows itself to create a session factory to be used in its repositories. Code looks something like this.
private static ISessionFactory sessionFactory;
private static Configuration configuration;
public static Configuration Configuration()
{
if (configuration == null)
{
configuration = new Configuration().Configure();
}
return configuration;
}
private static ISessionFactory SessionFactory
{
get
{
if (sessionFactory == null)
{
sessionFactory = Configuration().BuildSessionFactory();
}
return sessionFactory;
}
}
public static ISession GetCurrentSession()
{
if (!CurrentSessionContext.HasBind(SessionFactory))
{
CurrentSessionContext.Bind(SessionFactory.OpenSession());
}
return SessionFactory.GetCurrentSession();
}
So the repository calls the GetCurrentSession() method to get a ISession. Now this works fine but I am worried that it might not be thread safe. Can any one help me with an approach that will help me make it thread safe.
Few things to Note:
I have thought about configuring and building the SessionFactory in global.asax of the web applications on start event but the problem with this is that the common class library in question is used within 20 different applications so this will mean going to all the applications and updating the global.asax file now before I do this I wanted to put the question out there to see if there any other ways I can go about this. So that the common class library can configure its SessionFactory itself and yet be thread safe.
Thanks for reading this huge question. Will appericate any help.
The session factory is threadsafe, the session is not. Building the session factory needs to be protected:
private static object lockObject = new object();
private static ISessionFactory SessionFactory
{
get
{
lock (lockObject)
{
if (sessionFactory == null)
{
sessionFactory = Configuration().BuildSessionFactory();
}
return sessionFactory;
}
}
}
The session factory is created the first time a thread is requesting a session. This needs to be thread safe to avoid creating the session factory multiple times.
Creating the session by the session factory is thread safe, so you don't need to worry about that.
Sessions are not thread safe in NHibernate by design. So it should be ok as long as you have a session used by only one thread.
You can have one NHibernate SessionFactory for multiple threads as long as you have a separate NHibernate session for each thread
for more info have a look at the below link:
https://forum.hibernate.org/viewtopic.php?p=2373236&sid=db537baa5a57e3968abdda5cceec2a24
I suggest use one session for each Request like this:
public ISession GetCurrentSession()
{
HttpContext context = HttpContext.Current;
var currentSession = context.Items["session"] as ISession;
if( currentSession is null )
{
currentSession = SessionFactory.GetCurrentSession()
context.Items["session"] = currentSession;
}
return currentSession;
}
Following on from the comment by Stefan Steinegger, I think it would be more efficient to add a null check immediately before the lock, that way you don't need to lock every time if the sessionFactory has already been initialized.
private static object lockObject = new object();
private static ISessionFactory SessionFactory
{
get
{
if (sessionFactory != null)
{
return sessionFactory;
}
lock (lockObject)
{
if (sessionFactory == null)
{
sessionFactory = Configuration().BuildSessionFactory();
}
return sessionFactory;
}
}
}

Entity Framework Best Practices In Business Logic?

I am using the Entity framework for the first time, and would like to know if I am using in the best practice.
I have created a separate class in my business logic which will handle the entity context. the problem I have, is in all the videos I have seen they usually wrap the context in a using statement to make sure its closed, but obviously I can't do this in my business logic as the context will be closed before I can actually use it?
So is this ok what I'm doing? A couple of examples:
public IEnumerable<Article> GetLatestArticles(bool Authorised)
{
var ctx = new ArticleNetEntities();
return ctx.Articles.Where(x => x.IsApproved == Authorised).OrderBy(x => x.ArticleDate);
}
public IEnumerable<Article> GetArticlesByMember(int MemberId, bool Authorised)
{
var ctx = new ArticleNetEntities();
return ctx.Articles.Where(x => x.MemberID == MemberId && x.IsApproved == Authorised).OrderBy(x => x.ArticleDate);
}
I just want to make sure I'm not building something that's going to die when a lot of people use it?
It really depends on how to want to expose your repository/data store.
Not sure what you mean by "the context will be closed, therefore i cannot do business logic". Do your business logic inside the using statement. Or if your business logic is in a different class, then let's continue. :)
Some people return concrete collections from their Repository, in which case you can wrap the context in the using statement:
public class ArticleRepository
{
public List<Article> GetArticles()
{
List<Article> articles = null;
using (var db = new ArticleNetEntities())
{
articles = db.Articles.Where(something).Take(some).ToList();
}
}
}
Advantage of that is satisfying the good practice with connections - open as late as you can, and close as early as you can.
You can encapsulate all your business logic inside the using statement.
The disadvantages - your Repository becomes aware of business-logic, which i personally do not like, and you end up with a different method for each particular scenario.
The second option - new up a context as part of the Repository, and make it implement IDisposable.
public class ArticleRepository : IDisposable
{
ArticleNetEntities db;
public ArticleRepository()
{
db = new ArticleNetEntities();
}
public List<Article> GetArticles()
{
List<Article> articles = null;
db.Articles.Where(something).Take(some).ToList();
}
public void Dispose()
{
db.Dispose();
}
}
And then:
using (var repository = new ArticleRepository())
{
var articles = repository.GetArticles();
}
Or the third-option (my favourite), use dependency injection. Decouple all the context-work from your Repository, and let the DI container handle disposal of resources:
public class ArticleRepository
{
private IObjectContext _ctx;
public ArticleRepository(IObjectContext ctx)
{
_ctx = ctx;
}
public IQueryable<Article> Find()
{
return _ctx.Articles;
}
}
Your chosen DI container will inject the concrete ObjectContext into the instantiation of the Repository, with a configured lifetime (Singleton, HttpContext, ThreadLocal, etc), and dispose of it based on that configuration.
I have it setup so each HTTP Request gets given a new Context. When the Request is finished, my DI container will automatically dispose of the context.
I also use the Unit of Work pattern here to allow multiple Repositories to work with one Object Context.
You may have also noticed I prefer to return IQueryable from my Repository (as opposed to a concrete List). Much more powerful (yet risky, if you don't understand the implications). My service layer performs the business logic on the IQueryable and then returns the concrete collection to the UI.
That is my far the most powerful option, as it allows a simple as heck Repository, the Unit Of Work manages the context, the Service Layer manages the Business Logic, and the DI container handles the lifetime/disposal of resources/objects.
Let me know if you want more info on that - as there is quite a lot to it, even more than this surprisingly long answer. :)
I would have the ctx as a private variable within each class, then create a new instance of this each time and then dispose when finished.
public class ArticleService
{
private ArticleEntities _ctx;
public ArticleService()
{
_ctx = new ArticleEntities();
}
public IEnumerable<Article> GetLatestArticles(bool Authorised)
{
return _ctx.Articles.Where(x => x.IsApproved == Authorised).OrderBy(x => x.ArticleDate);
}
public IEnumerable<Article> GetArticlesByMember(int MemberId, bool Authorised)
{
return _ctx.Articles.Where(x => x.MemberID == MemberId && x.IsApproved == Authorised).OrderBy(x => x.ArticleDate);
}
public void Dispose()
{
_ctx.Dispose();
_ctx = null;
}
}
Then when calling this.
ArticleService articleService = new ArticleService();
IEnumerable<Article> article = articleService.GetLatestArticles(true);
articleService.Dispose(); // killing the connection
This way you can also add/update other objects within the same context and call a save method which saves any changes to the db through the Entity.
In my experience this code is not good, because you lose the capacity to navigate relationships through navigation properties.
public List<Articles> getArticles( ){
using (var db = new ArticleNetEntities())
{
articles = db.Articles.Where(something).ToList();
}
}
Using this approach you can't use the following code because a.Members is always null( db context is close and cant get data automatically).
var articles = Data.getArticles();
foreach( var a in articles ) {
if( a.Members.any(p=>p.Name=="miki") ) {
...
}
else {
...
}
}
}
Using only a global db context is a bad idea because you must use a delete changes function
in a point of your application yo do this but don't save changes and close the window
var article= globalcontext.getArticleByID(10);
article.Approved=true;
then in another point of application you make some operation and save
//..... something
globalcontext.saveChanges();
in this case previous article approved property is set to modified by entity framework. When you save, approved is set true!!!
Best approach for me is use 1 context per class
You can pass context to another external method if you need
class EditArticle {
private DbEntities de;
private currentAricle;
public EditArticle() {
de = new DbEntities; //inizialize on new istance
}
loadArticleToEdit(Articele a){
// a is from another context
currentArticle= de.Article.Single(p=>p.IdArticle==a.IdArticle){
}
private saveChanges(){
...
pe.saveChanges();
}
}
What you can also do is store your context at a higher level.
E.g., you can have a static class storing the current context:
class ContextManager
{
[ThreadStatic]
public static ArticleEntities CurrentContext;
}
Then, somewhere outside you do something like this:
using (ContextManager.CurrentContext = new ArticleEntities())
{
IEnumerable<Article> article = articleService.GetLatestArticles(true);
}
Then, inside the GetLastestArticles, you just use the same ContextManager.CurrentContext.
Of course, this is just the basic idea. You can make this a lot more workable by using service providers, IoC and such.
You can start preparing Entity Framework from data access layer by creating a generic repository class for all required Entity Framework functions. Then you can used it in Business layer (Encapsulated)
Here are the best practices that I have used for Entity Framework in data, business, and UI layers
Techniques used for this practice:
Applying SOLID architecture principles
Using Repository design pattern
Only one class to go (and you will find it ready)

Categories