I created console application, database, model, XML-file and then I wrote this code
using System;
using System.Reflection;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
namespace NHibernateDemo
{
internal class Program
{
static void Main(string[] args)
{
try
{
var cfg = new Configuration();
cfg.DataBaseIntegration(x =>
{
x.ConnectionString = "Server=.; Database=NHibernateDemo; Integrated Security = SSPI;";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
});
cfg.AddAssembly(Assembly.GetExecutingAssembly());
var sessionFactory = cfg.BuildSessionFactory();
using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
var customers = session.CreateCriteria<Customer>()
.List<Customer>();
foreach (var customer in customers)
{
Console.WriteLine("{0} {1}", customer.FirstName, customer.LastName);
}
tx.Commit();
Console.WriteLine("Enter any key to exit...");
Console.ReadKey();
}
}
catch (Exception e)
{
}
}
}
}
I didn't get any error and any exception, but I didn't get any information from database too, just string "Enter any key to exit..." in console.
What's wrong?
UPD
XML-file
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mappin xmlns="urn:nhibernate-mapping-2.2"
assembly="NHibernateDemo"
namespace="NHibernateDemo">
<class name="Customer">
<id name="Id">
<generator class="native" />
</id>
<property name="FirstName"/>
<property name="LastName"/>
</class>
</hibernate-mappin>
Have you added the xml mapping files to the Assembly.GetExecutingAssembly())? You have to make the embedded resource. Otherwise you will have the behavoir you are describing.
Go to the properties of the files to change the build action.
The root tag of a mapping XML file has to be hibernate-mapping (note the "g" at the end).
Related
I wanted to test whether my entities can be persisted to the database or not, so I came across this article:
http://www.codethinked.com/nhibernate-20-sqlite-and-in-memory-databases
My code to initialize the session factory is the same the one in the article:
public class NHibernateInMemoryTestFixtureBase
{
protected static ISessionFactory sessionFactory;
protected static Configuration configuration;
public static void InitalizeSessionFactory(params Assembly[] assemblies)
{
if (sessionFactory != null)
return;
var properties = new Dictionary<string, string>();
properties.Add("connection.driver_class", "NHibernate.Driver.SQLite20Driver");
properties.Add("dialect", "NHibernate.Dialect.SQLiteDialect");
properties.Add("connection.provider", "NHibernate.Connection.DriverConnectionProvider");
properties.Add("connection.connection_string", "Data Source=:memory:;Version=3;New=True;");
properties.Add("connection.release_mode", "on_close");
configuration = new Configuration();
configuration.Properties = properties;
foreach (Assembly assembly in assemblies)
{
configuration = configuration.AddAssembly(assembly);
}
sessionFactory = configuration.BuildSessionFactory();
}
public ISession CreateSession()
{
ISession openSession = sessionFactory.OpenSession();
IDbConnection connection = openSession.Connection;
new SchemaExport(configuration).Execute(false, true, false, true, connection, null);
return openSession;
}
}
And here's my test:
[Test]
public void IWillChangeThisNameLater()
{
InitalizeSessionFactory(typeof(LogRepository).Assembly);
var session = this.CreateSession();
Log log = Log.New("a", "b", "I");
session.Save(log);
session.Flush();
Assert.Greater(log.IDColumn, 0);
}
And the problem is, I removed the "a" property of Log from the log.hbm.xml and session.Save(log) is not throwing an exception or anything, it just works...
This must be obvious and on porpose, but I fail to find out why that is, how can it save it if is not mapped, is that how the in memory database work? how can I test my mapping then?
I mainly did this in-memory test so that I can know right away if a valid entity is failing to persist, of course that would include missing properties on the mapping file.
Any thoughts will be appreciated.
EDIT:
As requested,
the Log entity definition:
public class Log : DomainBase<Log, ILogRepository<Log>>
{
private int logId;
private string tableName;
private string field;
private string userLogin;
protected Log()
{
}
protected Log(string tableName, string field, string userLogin)
{
TableName = tableName;
Field = field;
UserLogin = userLogin;
}
public virtual int LogId { get; set; }
public virtual string TableName { get; set; }
public virtual string Field { get; set; }
public virtual string UserLogin { get; set; }
}
the Log Mapping:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="DomainProject" table="Log" lazy="true">
<id name="logId" column="ID" type="int">
<generator class="native" />
</id>
<property name="TableName" column="TableName" type="string" />
<property name="Field" column="Field" type="string" />
<property name="UserLogin" column="UserLogin" type="string" />
</class>
</hibernate-mapping>
If a class contains a property that is not mentioned in the mappings, NHibernate will ignore the property.
I'm following the NHibernate getting started tutorial: "Your first NHibernate based application". I'm at the point where I create a Product object then use Session.get() to prove I can read the object.
It works fine with SQL Server Ce, but I'm getting an exception when I try to use DB2. (The SQL Server Ce version works - that is. There are some minor changes between the versions like int instead of GUID for the Id.)
I'm very experienced with Hibernate and SQL databases. This is my first experience with NHibernate and DB2. (Coming from the Java world). I'd appreciate any suggestions, especially from the (evidently few) people who are using NHibernate on DB2.
Rob
The full exception is
Test method Examples.DB2.NHibernateExamples.Can_add_new_product threw
exception: NHibernate.Exceptions.GenericADOException: could not load
an entity: [Examples.DB2.Domain.Product#1][SQL: SELECT product0_.Id as
Id1_0_, product0_.Name as Name1_0_, product0_.Category as
Category1_0_, product0_.Discontinued as Disconti4_1_0_ FROM Product
product0_ WHERE product0_.Id=?] ---> System.IndexOutOfRangeException:
Invalid index 0 for this DB2ParameterCollection with Count=0.
This is happening in the Get(...) call in the following code:
[TestInitialize]
public void TestInitialize()
{
TestFixtureSetup();
SetupContext();
}
[TestMethod]
public void Can_add_new_product()
{
var product = new Product { Id = 1, Name = "Apple", Category = "Fruits"};
using (ISession session = _sessionFactory.OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
session.Save(product);
transaction.Commit();
}
}
using (ISession session = _sessionFactory.OpenSession())
{
//var query = session.CreateQuery("from Product");
//var products = query.List<Product>();
//Assert.AreEqual(1, products.Count);
var fromDb = session.Get<Product>(product.Id);
Assert.IsNotNull(fromDb);
Assert.AreNotSame(product, fromDb);
Assert.AreEqual(product.Name, fromDb.Name);
Assert.AreEqual(product.Category, fromDb.Category);
}
}
private void TestFixtureSetup()
{
_configuration = new Configuration();
_configuration.Configure();
_configuration.AddAssembly(typeof (Domain.Product).Assembly);
_sessionFactory = _configuration.BuildSessionFactory();
}
private void SetupContext()
{
new SchemaExport(_configuration).Execute(true, true, false);
}
The exception seems to indicate that the Id paramter isn't being passed to the DB2 query. If I uncomment the three lines before the Get(), it works fine since the row is already cached and the Get() doesn't actually go to the database.
Here is the definition of Product.cs:
using System;
namespace Examples.DB2.Domain
{
class Product
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual string Category { get; set; }
public virtual bool Discontinued { get; set; }
}
}
Here is Product.hbm.xml:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Examples.DB2"
namespace="Examples.DB2.Domain">
<class name="Product">
<id name="Id">
<generator class="native" />
</id>
<property name="Name" />
<property name="Category" />
<property name="Discontinued" type="YesNo"/>
</class>
</hibernate-mapping>
Here is hibernate.cfg.xml:
<?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="dialect">NHibernate.Dialect.DB2Dialect</property>
<property name="connection.driver_class">NHibernate.Driver.DB2Driver</property>
<property name="connection.connection_string">Database=SAMPLE; UID=DEV; PWD=password</property>
<property name="show_sql">true</property>
</session-factory>
</hibernate-configuration>
I'm working in Visual Studio 2010 Premium on Windows 7. I'm using DB2 Express-C 9.7.4.
Ok,
I found the answer ... not exactly sure of the solution yet, but in the final release of NHibernate they added a call to AdoNet\AbstractBatcher.cs called RemoveUnusedCommandParameters. This procedure calls Driver.RemoveUnusedCommandParameters.
My solution for now is just to comment out this call and let the function do nothing.
I will bring this up with the nhusers group and see if there is a better long term solution.
thanks
dbl
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.
I've been trying all day to get one of my object to be saved with versions but to no avail. Please point out what I'm doing wrong, as I've tried SaveOrUpdate, Merge() and Update() after a Clear() call.
The business object:
public class MappedTest
{
public virtual Guid TestID { get; set; }
public virtual int VersionID { get; set; }
public virtual byte[] Content { get; set;}
public virtual DateTime DateSaved { get; set; }
}
The mapping:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping ...>
<class name="TestImp.Definition.MappedTest, PythonTest" table="Tests">
<id name="TestID" unsaved-value="00000000-0000-0000-0000-000000000000">
<generator class="guid"/>
</id>
<version name="VersionID" column="VersionID" />
<property name="Content" column="TestObject" type="BinaryBlob"/>
<property name="DateSaved" column="Date"/>
`
The actual code:
using (var session = new Configuration().Configure().BuildSessionFactory().OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
if(session.Get<MappedTest>(mappedTest.TestID) == null)
{
session.Save(mappedTest);
}
else
{
session.Clear();
session.Update(mappedTest);
}
transaction.Commit();
}
}`
Thanks.
For insert try just with:
using (var session = new Configuration().Configure().BuildSessionFactory().OpenSession())
{
MappedTest mappedTest =new MappedTest();
using (ITransaction transaction = session.BeginTransaction())
{
session.SaveOrUpdate(mappedTest);
transaction.Commit();
}
}
for update:
using (var session = new Configuration().Configure().BuildSessionFactory().OpenSession())
{
MappedTest mappedTest =session.Get<MappedTest>(..an Id..);
mappedTest.YourProperty="newValue";
using (ITransaction transaction = session.BeginTransaction())
{
session.SaveOrUpdate(mappedTest);
transaction.Commit();
}
}
If you need it try use a session.Flush() to force database operations.
Another possibility that took me some time to realize and is not covered yet on this thread: In such case, check if your mapper is set on ReadOnly. NHibernate does not tell anything when asked to save or update with a ReadOnly mapper.
I tried an example from NHibernate in Action book and when I try to run the app, it throws an exception saying "Could not compile the mapping document:
HelloNHibernate.Employee.hbm.xml"
Below is my code,
Employee.hbm.xml
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true">
<class name="HelloNHibernate.Employee, HelloNHibernate" lazy="false" table="Employee">
<id name="id" access="field">
<generator class="native"/>
</id>
<property name="name" access="field" column="name"/>
<many-to-one access="field" name="manager" column="manager" cascade="all"/>
</class>
</hibernate-mapping>
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using System.Reflection;
using NHibernate.Cfg;
namespace HelloNHibernate
{
class Program
{
static void Main(string[] args)
{
CreateEmployeeAndSaveToDatabase();
UpdateTobinAndAssignPierreHenriAsManager();
LoadEmployeesFromDatabase();
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
static void CreateEmployeeAndSaveToDatabase()
{
Employee tobin = new Employee();
tobin.name = "Tobin Harris";
using (ISession session = OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
session.Save(tobin);
transaction.Commit();
}
Console.WriteLine("Saved Tobin to the database");
}
}
static ISession OpenSession()
{
if (factory == null)
{
Configuration c = new Configuration();
c.AddAssembly(Assembly.GetCallingAssembly());
factory = c.BuildSessionFactory();
}
return factory.OpenSession();
}
static void LoadEmployeesFromDatabase()
{
using (ISession session = OpenSession())
{
IQuery query = session.CreateQuery("from Employee as emp order by emp.name asc");
IList<Employee> foundEmployees = query.List<Employee>();
Console.WriteLine("\n{0} employees found:", foundEmployees.Count);
foreach (Employee employee in foundEmployees)
Console.WriteLine(employee.SayHello());
}
}
static void UpdateTobinAndAssignPierreHenriAsManager()
{
using (ISession session = OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
IQuery q = session.CreateQuery("from Employee where name='Tobin Harris'");
Employee tobin = q.List<Employee>()[0];
tobin.name = "Tobin David Harris";
Employee pierreHenri = new Employee();
pierreHenri.name = "Pierre Henri Kuate";
tobin.manager = pierreHenri;
transaction.Commit();
Console.WriteLine("Updated Tobin and added Pierre Henri");
}
}
}
static ISessionFactory factory;
}
}
Employee.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace HelloNHibernate
{
class Employee
{
public int id;
public string name;
public Employee manager;
public string SayHello()
{
return string.Format("'Hello World!', said {0}.", name);
}
}
}
App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="nhibernate" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.3300.0, Culture=neutral
PublicKeyToken=b77a5c561934e089"/>
</configSections>
<nhibernate>
<add key="hibernate.show_sql" value="false"/>
<add key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider"/>
<add key="hibernate.dialect" value="NHibernate.Dialect.MsSql2005Dialect"/>
<add key="hibernate.connection.driver_class" value="NHibernate.Driver.SqlClientDriver"/>
<add key="hibernate.connection.connection_string" value="Server=(local)\SQLEXPRESS; Database=HelloNHibernate;Integrated Security=SSPI;"/>
</nhibernate>
</configuration>
Let's open the Matryoshka doll a bit further, and solve the other problem:
In this line:
<section name="nhibernate" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.3300.0, Culture=neutral
PublicKeyToken=b77a5c561934e089"/>
you're missing a comma between "neutral" and "PublicKeyToken".
Give that a try.
Do you have a manager class and mapping defined? The
<many-to-one access="field" name="manager" column="manager" cascade="all"/>
line is looking for one. If the "manager" field is supposed to be an Employee, then you probably want:
<many-to-one access="field" name="manager" column="manager" class="HelloNHibernate.Employee, HelloNHibernate" cascade="all"/>
I think I see the problem now. The problem appears to be in this line:
<add key="hibernate.connection.connection_string" value="SQL2008EXPRESS" Database="HelloNHibernate;Integrated Security=SSPI;User Id=SQL2008"/>
The connection string is malformed, and it's throwing off the XML parser. Since the "value" attribute ends early, the XML parser thinks "Database=" is another XML attribute, but it's not one it recognizes, so it chokes. The solution is to fix the connection string.
The line should probably read:
<add key="hibernate.connection.connection_string" value="Server=(local)\SQLEXPRESS; Database=HelloNHibernate;Integrated Security=SSPI;"/>
This is assuming you're using Windows authentication; given that this is a learning project, that's probably the best way to go. If you're using SQL Server authentication, use this line instead:
<add key="hibernate.connection.connection_string" value="Server=(local)\SQLEXPRESS; Database=HelloNHibernate; User Id=theusername; Password=thepassword"/>
An aside: I don't think NHibernate 1.2.1GA has a SQL Server 2008 dialect. Instead, use NHibernate.Dialect.MsSql2005Dialect.