NHibernate Object reference not set to an instance of an object - asp.net-mvc-4

This is my first time using NHibernate and i am trying to create an application using MVC 4, here is my configuration file:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" >
<session-factory >
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="connection.connection_string">Data Source=.\SQLEXPRESS;Initial Catalog=loc;Persist Security Info=True;Trusted_Connection=Yes;Pooling=yes;connection lifetime=300;User Id=sa;Password=###</property>
<property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property>
<property name="show_sql">false</property>
and the mapping file:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="HelloWorldHib"
namespace="HelloWorldHib.Mappings">
<class name="Product" table="Products">
<id name="Id" column="Id">
<generator class="native"></generator>
</id>
<property name="Name"></property>
<property name="Category"></property>
<property name="IsDis"></property>
</class>
</hibernate-mapping>
And the helper:
public class NHibernateHelper
{
private static ISessionFactory _sessionFactory;
private static Configuration cfg;
private static ISessionFactory SessionFactory
{
get
{
if (_sessionFactory == null)
{
cfg.Configure(HttpContext.Current.Server.MapPath("~/hibernate.cfg.xml"));
cfg.AddDirectory(new System.IO.DirectoryInfo(HttpContext.Current.Server.MapPath(#"~/Mappings")));
cfg.AddAssembly(typeof(Product).Assembly);
_sessionFactory = cfg.BuildSessionFactory();
if (_sessionFactory == null)
throw new InvalidOperationException("session factory could not be built");
}
return _sessionFactory;
}
}
public static ISession OpenSession()
{
ISession session;
session = _sessionFactory.OpenSession();
if (session == null)
throw new InvalidOperationException("session could not be opend");
return session;
}
}
When i run my app i get Object reference not set to an instance of an object on this line session = _sessionFactory.OpenSession()
The table exist in the database, what is the problem?
Thanks

Means that the variable _sessionFactory is null. You should use the property SessionFactory instead which will also initialize the _sessionFactory variable.
session = SessionFactory.OpenSession();

Related

Cascade Save - StaleObjectStateException: Row was updated or deleted by another transaction

Having an issue with updating the NHibernate version. Current version is 3.3.1.4000 and trying to update to 4.
After updating the unit test which does save with cascade fails with:
NHibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [NHibernateTests.TestMappings.ProductLine#cdcaf08d-4831-4882-84b8-14de91581d2e]
The mappings:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernateTests" namespace="NHibernateTests.TestMappings">
<class name="Product" lazy="false" table="UserTest">
<id name="Id">
<generator class="guid"></generator>
</id>
<version name="Version" column="Version" unsaved-value="0"/>
<property name="Name" not-null="false"></property>
<property name="IsDeleted"></property>
<bag name="ProductLines" table="ProductLine" inverse="true" cascade="all" lazy="true" where="IsDeleted=0" >
<cache usage="nonstrict-read-write" />
<key column="UserId" />
<one-to-many class="ProductLine" />
</bag>
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernateTests" namespace="NHibernateTests.TestMappings">
<class name="ProductLine" where="IsDeleted=0" lazy="false">
<cache usage="nonstrict-read-write" />
<id name="Id">
<generator class="guid"></generator>
</id>
<version name="Version" column="Version" unsaved-value="0"/>
<property name="IsDeleted"></property>
<many-to-one name="Product" class="Product" column="UserId" not-null="true" lazy="proxy"></many-to-one>
</class>
</hibernate-mapping>
Classes:
public class Product
{
public Guid Id { get; set; }
public int Version { get; set; }
public bool IsDeleted { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
public IList<ProductLine> ProductLines { get; private set; }
public Product()
{
ProductLines = new List<ProductLine>();
}
}
public class ProductLine
{
public Guid Id { get; set; }
public int Version { get; set; }
public bool IsDeleted { get; set; }
public Product Product { get; set; }
}
The test:
[TestMethod]
public void CascadeSaveTest()
{
var product = new Product
{
Id = Guid.NewGuid(),
Name = "aaa",
IsActive = true
};
var productLine = new ProductLine
{
Id = Guid.NewGuid(),
Product = product,
};
product.ProductLines.Add(productLine);
using (var connection = new RepositoryConnection())
{
using (var repositories = new Repository<Product>(connection))
{
repositories.Create(product);
//the below just calls the Session.Transaction.Commit();
connection.Commit(); //NH3.3.1.400 passes, NH4 fails
}
}
}
Thanks for you ideas in advance.
Well, I guess I have now understood what causes the error with NH 4. And If I am right, that is a bit contrived case causing this behavior to be hard to qualify as a bug.
In your example, products lines are mapped through a bag. A bag can contains duplicates, which requires an intermediate table between Product and ProductLine. (Something like a ProductProductLine table with an UserId (ProductId) column, and a ProductLineId column.)
You have set this intermediate table as being the ProductLine table. I suspect the commit to db causes NHibernate to insert the product, then the product line, then to try to insert the relationship by inserting again in ProductLine table. (You may check that by profiling SQL queries on your db.)
Things are a bit muddy, since doc states (emphasis is mine):
table (optional - defaults to property name) the name of the
collection table (not used for one-to-many associations)
But then, how to honor the bag semantics allowing duplicates in the collection? From the same doc:
A bag is an unordered, unindexed collection which may contain the same
element multiple times.
Anyway, within your example, you really should map your one-to-many with a set, as shown in doc.
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernateTests" namespace="NHibernateTests.TestMappings">
<class name="Product" lazy="false" table="UserTest">
<id name="Id">
<generator class="guid"></generator>
</id>
<version name="Version" column="Version" unsaved-value="0"/>
<property name="Name" not-null="false"></property>
<property name="IsDeleted"></property>
<set name="ProductLines" inverse="true" cascade="all" lazy="true" where="IsDeleted=0" >
<cache usage="nonstrict-read-write" />
<key column="UserId" />
<one-to-many class="ProductLine" />
</set>
</class>
</hibernate-mapping>
And change your collection type for using .Net fx 4 System.Collections.Generic.ISet<T>.
public ISet<ProductLine> ProductLines { get; private set; }
public Product()
{
ProductLines = new HashSet<ProductLine>();
}
If this causes your trouble to disappear, it would mean something has changed in bag handling in NH 4. But should we consider this change as being a bug? Not sure, since using a bag in this case does not look right for me.
Drilling it further down turned out that NHibernate4 has problems identifying whether it is a new entity or an already existent when concerned with Cascade.
With the scenario in question it was calling a SQL Update for the ProductLine, rather than Create.
It works fine with the below changes, however I'm quite puzzled with such a changes in between NHibernate versions.
Change to ProductLine Mapping
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernateTests" namespace="NHibernateTests.TestMappings">
<class name="ProductLine" where="IsDeleted=0" lazy="false">
<cache usage="nonstrict-read-write" />
<!-- here comes the updated line -->
<id name="Id" type="guid" unsaved-value="00000000-0000-0000-0000-000000000000">
<generator class="guid"></generator>
</id>
<version name="Version" column="Version" unsaved-value="0"/>
<property name="IsDeleted"></property>
<many-to-one name="Product" class="Product" column="UserId" not-null="true" lazy="proxy"></many-to-one>
</class>
</hibernate-mapping>
Change to test method
[TestMethod]
public void CascadeSaveTest()
{
var product = new Product
{
Id = Guid.NewGuid(),
Name = "aaa",
IsActive = true
};
var productLine = new ProductLine
{
Id = Guid.Empty, //The updated line
Product = product,
};
product.ProductLines.Add(productLine);
using (var connection = new RepositoryConnection())
{
using (var repositories = new Repository<Product>(connection))
{
repositories.Create(product);
connection.Commit();
}
}
}

Data is not really storing database in nhibernate

I am writing a simple program using nhibernate
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using NHibernate.Cfg;
using System.Data.SqlServerCe;
using NHibernate.ByteCode.LinFu;
namespace FirstSolution
{
class Program
{
static void Main(string[] args)
{
Product p = new Product();
p.id = "padu";
p.name = "Sayan";
p.category = "Bogus";
Configuration cfg = new Configuration();
cfg.AddXmlFile("C:/Users/win7/Documents/Visual Studio 2008/Projects/FirstSolution/FirstSolution/Product.hbm.xml");
try
{
using (ISessionFactory factory = cfg.BuildSessionFactory())
{
using (ISession session = factory.OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
// Tell NHibernate that this object should be saved
session.Save(p);
// commit all of the changes to the DB and close the ISession
session.Flush();
transaction.Commit();
session.Close();
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
string s;
s = Console.ReadLine();
}
}
}
App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="hibernate-configuration"
type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" />
</configSections>
<connectionStrings>
<add name="FirstSolution.Properties.Settings.Database1ConnectionString"
connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory| \Database1.mdf;Integrated Security=True;User Instance=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="dialect">NHibernate.Dialect.MsSqlCeDialect</property>
<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="proxyfactory.factory_class">
NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu
</property>
<property name="connection.connection_string">Data Source=.\SQLEXPRESS; AttachDBFilename=|DataDirectory|Database1.mdf;Integrated Security=true;User Instance=true;</property>
<property name="show_sql">true</property>
<mapping assembly="FirstSolution"/>
</session-factory>
</hibernate-configuration>
</configuration>
Product.hbm.xml
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="FirstSolution" assembly="FirstSolution">
<class name="Product" table="UserTable" lazy="false">
<id name="id" column="id" type="String" length="10">
<generator class="assigned"/>
</id>
<property name="name" column="name" type="String" length="10"/>
<property name="category" column="category" type="String" length="10"/>
</class>
</hibernate-mapping>
Product.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace FirstSolution
{
public class Product
{
public String id { get; set; }
public String name { get; set; }
public String category { get; set; }
}
}
Program is running without any exception. Generated sql is showing on console. But no data is saved in UserTable of Database1.mdf
Database1.mdf is being copied to the /bin/Debug folder when the application is built and the data is saved there.
Hmm. I'm surprised that you don't get exceptions. The Product class must have virtual properties, otherwise it won't work.
Also, I see you're using the MsSqlCeDialect. I haven't used SqlExpress but SqlExpress != SqlCe. Trying using MsSql2005Dialect or MsSql2005Dialect.

Nhibernate one-to-one mapping

Hello guys I've tried searching for a solution to this problem for a period of time. Couldn't find it.
I have two classes which I will simplify. My problem is that i want a unidirectional one-to-one mapping between Player and Clan. Now I saw examples which have foreign key in ther id. But I don't understand it. This mapping is not producing a column in my Clans table for ClanLeader... Am i missing something? Thank you all for help.
public class Clan{
private Int32 id;
public virtual Int32 Id
{
get { return id; }
set { id = value; }
}
private string name;
public virtual string Name
{
get { return name; }
set { name = value; }
}
private Player clanLeader;
public virtual Player ClanLeader
{
get { return clanLeader; }
set { clanLeader = value; }
}
}
Then we have mapping for Clan:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="NHibernateSQLite"
namespace="NHibernateSQLite" >
<class name="GamingOrganizerDomainModel.Clan, GamingOrganizerDomainModel" table="Clans" lazy="false">
<id name="id" access="field" column="Clan_ID" type="Int32">
<generator class="native"></generator>
</id>
<property name="Name" column="Clan_Name" unique-key="ClanNameConstraint" type="String"/>
<one-to-one name="ClanLeader" class="GamingOrganizerDomainModel.Player, GamingOrganizerDomainModel" />
</class>
</hibernate-mapping>
Next is the class Player:
public class Player{
private Int32 id;
public virtual Int32 Id
{
get { return id; }
set { id = value; }
}
private string nickname;
public virtual string Nickname
{
get { return name; }
set { name = value; }
}
}
And mapping for Player:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="NHibernateSQLite"
namespace="NHibernateSQLite" >
<class name="GamingOrganizerDomainModel.Player, GamingOrganizerDomainModel" table="Players" lazy="false">
<id name="id" column="Player_ID" access="field" type="Int32">
<generator class="native" />
</id>
<property name="nickname" access="field" column="Nickname"/>
</class>
</hibernate-mapping>
Unidirectional one to one relation should be mapped as "many-to-one" element. "one-to-one" is used for bidirectional one to one. See this post for more details. Howerver there are ConfORM mappings as well the article is crystal clear.
You need make only one change in your Clan mapping:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="GamingOrganizerDomainModel"
namespace="GamingOrganizerDomainModel" >
<class name="Clan" table="Clans" lazy="false">
<id name="id" access="field" column="Clan_ID" type="Int32">
<generator class="native"></generator>
</id>
<property name="Name" column="Clan_Name" unique-key="ClanNameConstraint" type="String"/>
<many-to-one name="ClanLeader" class="Player" />
</class>
You do not need to write assembly qualified class name in the mapping. Assembly and namespace attributes of hibernate-mapping element specify default namespace and assembly where NH tries to find specific class.

Nhibernate get collection by ICriteria

colleagues. I've got a problem at getting my entity. Mapping:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Clients.Core"
namespace="Clients.Core.Domains">
<class name="Sales, Clients.Core" table='sales'>
<id name="Id" unsaved-value="0">
<column name="id" not-null="true"/>
<generator class="native"/>
</id>
<property name="Guid">
<column name="guid"/>
</property>
<set name="Accounts" table="sales_users" lazy="false">
<key column="sales_id" />
<element column="user_id" type="Int32" />
</set>
</class>
Domain:
public class Sales : BaseDomain
{
ICollection<int> accounts = new List<int>();
public virtual ICollection<int> Accounts
{
get { return accounts; }
set { accounts = value; }
}
public Sales() { }
}
I want get query such as
SELECT *
FROM sales s
INNER JOIN sales_users su on su.sales_id=s.id
WHERE su.user_id=:N
How can i do this through ICriterion object?
Thanks a lot.
This is what I think the answer should be:
public IEnumerable<Sales> GetSalesForUser(int userId)
{
return session.CreateCriteria<Sales>()
.CreateAlias("Accounts", "accounts")
.Add(Restrictions.Eq("accounts.UserId", "userId"))
.List<Sales>();
}
But I'm confused by your model. It appears that Accounts has a many-to-many relationship with Sales, but you haven't mapped it that way. I'm not sure how to filter an int collection (HashSet in this case). You could try:
public IEnumerable<Sales> GetSalesForUser(int userId)
{
return session.CreateCriteria<Sales>()
.Add(Restrictions.Eq("Accounts", userId))
.List<Sales>();
}
var sales = session.CreateCriteria(typeof(Sales))
.SetFetchMode("Accounts", FetchMode.Join)
.SetResultTransformer(Transformers.DistinctRootEntity)
.List<Sales>();

Getting started with NHibernate

I am trying to develop my Hello World program in NHibernate.
My codes are as follows:
MyClass.cs
----------
using System.Collections.Generic;
using System.Text;
using System;
using NHibernate.Collection;
using NHibernate.Mapping;
using Iesi.Collections;
namespace NHibernate__MyClass
{
public class MyClass
{
int id;
string name;
int _value;
public MyClass()
{
id = 0;
name = "";
_value = 0;
}
public virtual int Id
{
get { return id; }
set { id= value; }
}
public virtual string Name
{
get { return name; }
set { name= value; }
}
public virtual int Value
{
get { return _value; }
set { _value= value; }
}
}
}
MyClass.hbm.xml
---------------
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="NHibernate__MyClass" assembly="NHibernate__MyClass">
<class name="MyClass" table="MyClass">
<id name="Id">
<column name="ID" sql-type="int" not-null="true"/>
<generator class="native" />
</id>
<property name="Name">
<column name="Name" not-null="true" />
</property>
<property name="Value">
<column name="Value" not-null="true" />
</property>
</class>
</hibernate-mapping>
Program.cs
----------
using System;
using System.Collections.Generic;
using System.Text;
using NHibernate;
using NHibernate.Cfg;
namespace NHibernate__MyClass
{
class Program
{
static void Main(string[] args)
{
MyClass myClass = new MyClass();
myClass.Id = 1;
myClass.Name = "Hello World!";
myClass.Value = 100;
ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory();
ISession session = sessionFactory.OpenSession();
session.BeginTransaction();
session.Save(myClass);
session.Transaction.Commit();
Console.ReadLine();
}
}
}
App.config
----------
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section
name="hibernate-configuration"
type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate"
/>
</configSections>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="dialect">NHibernate.Dialect.MsSql2000Dialect</property>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.connection_string">Data Source=.\SQLEXPRESS;Initial Catalog=NHibernate;Integrated Security=True</property>
<mapping assembly="NHibernate__MyClass" />
</session-factory>
</hibernate-configuration>
</configuration>
SQL Table
---------
CREATE TABLE [dbo].[MyClass](
[ID] [int] NOT NULL,
[Name] [varchar](50) NOT NULL,
[value] [int] NOT NULL
) ON [PRIMARY]
But this program is generating an Exception:
Exception message : {"could not insert: [NHibernate__MyClass.MyClass][SQL: INSERT INTO MyClass (Name, Value) VALUES (?, ?); select SCOPE_IDENTITY()]"}
Inner Exception Message : {"Cannot insert the value NULL into column 'ID', table 'NHibernate.dbo.MyClass'; column does not allow nulls. INSERT fails.\r\nThe statement has been terminated."}
What can be the problem?
NHibernate DLL version = 2.0.0.2002
Because of this tag in your mapping file
<generator class="native" />
In SQL you need to set the ID field in that table to an identity.
You can alternatively have nHibernate generate identity fields.