NHibernate SchemaExport.Execute does not create table - c#

Learning NHibernate by following this tutorial Your first NHibernate based application and I got to the point where you call
new SchemaExport(cfg).Execute(true, true, false);
in a test method to export the schema (create the Product table) for verifying NHibernate was set up correctly
[Test]
public void Can_generate_schema()
{
var cfg = new Configuration();
cfg.Configure();
cfg.AddAssembly(typeof(Product).Assembly);
new SchemaExport(cfg).Execute(true, true, false);
}
The mapping
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="MyFirstNHibernateProject" namespace="MyFirstNHibernateProject.Domain">
<class name="Product">
<id name="Id">
<generator class="guid"></generator>
</id>
<property name="Name"></property>
<property name="Category"></property>
<property name="Discontinued"></property>
</class>
</hibernate-mapping>
The configuration
<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.SqlServerCeDriver</property>
<property name="connection.connection_string">Data Source=MyFirstNHibernateProject.sdf</property>
<property name="show_sql">true</property>
</session-factory>
</hibernate-configuration>
The test passed and I can even see the output sql that create table but the table is not being created in the database (sql server compact), I refreshed the db in server explorer and it is still empty.
I have checked these posts
NHibernate SchemaExport not creating table
NHibernate SchemaExport does not create tables when “script” is false
NHibernate does not create Tables
but none of them solve my problem.
any ideas?

I would suggest to use full path in the connection string:
// instead of this
<property name="connection.connection_string"
>Data Source=MyFirstNHibernateProject.sdf</property>
// we should use
<property name="connection.connection_string"
>Data Source=C:\MyFirstNHibernateProject\MyFirstNHibernateProject.sdf</property>
Where the "C:\MyFirstNHibernateProject\" should be the full path to the "MyFirstNHibernateProject.sdf"
Also, in case you are suing CE 4.0 I would suggest to use this dialect:
<property name="dialect">NHibernate.Dialect.MsSqlCe40Dialect</property>

Related

How to create mapping for additional class inside some class?

I have two classes: Order and User
Order has User class inside of it:
[DataMember]
public virtual User User { get; set; }
I have NHibernate mapping for both of them:
For User:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Purchasing" namespace="Purchasing.Other">
<class name="User" table="tUser">
<id name="RID">
<column name="RID" sql-type="bigint"/>
<generator class="native"/>
</id>
<property name="Created"/>
<property name="Modified"/>
<property name="UserName"/>
<property name="Email"/>
<property name="ExternalUserId"/>
</class>
</hibernate-mapping>
And I tried to add User class to Order mapping, BUT looks like something is wrong:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Purchasing" namespace="Purchasing.Other">
<class name="Order" table="tOrder">
<id name="Id">
<column name="OrderId" sql-type="bigint"/>
<generator class="native" />
</id>
<property name="DataOwnerId" />
<property name="UserId" />
<property name="OrderNo"/>
<property name="FirstTaken"/>
<property name="DateRequired" />
<property name="ExternalOrderId" />
<many-to-one name="User" class="User" property-ref="ExternalUserId">
<column name="UserId" not-null="false"/>
</many-to-one>
</class>
</hibernate-mapping>
I have a situation, when, writing Order in tOrder database, I also need to write its User to tUser database.
But looks like it didn't work. (Order mapping without User map works fine).
How in this situation mapping should look correctly, and what am I missing?
P.S Sorry for my bad English.
If we want to persist User with its Order, we can use cascading setting:
5.1.10. many-to-one
An ordinary association to another persistent class is declared using a many-to-one element. The relational model is a many-to-one association. (It's really just an object reference.)
<many-to-one
name="PropertyName" (1)
...
cascade="all|none|save-update|delete" (4)
...
/>
(4) cascade (optional): Specifies which operations should be cascaded from the parent object to the associated object.
So the mapping could be like this:
<many-to-one name="User" class="User"
property-ref="ExternalUserId"
cascade="save-update"
column="UserId" not-null="false"
/>
Now, we only have to be sure, that we try to find a user (it could be existing)
var user = session.Get<User>(userId);
if(user == null)
{
user = new User { ... };
}
And then we can assing that user to the Order
var order = new Order { ... };
order.User = user;
and calling session to persist Order - user will be as well:
session.SaveOrUpdae(order);
NOTE: if you can reference user by its native ID ... it would be better. Mapping then would look like:
<many-to-one name="User" class="User"
cascade="save-update"
column="RID" not-null="false"
/>
Mapping with property-ref should be used exceptionally

Why can't I call BuildSessionFactory since the update from NHibernate 2 to 3.3.1?

Today I updated my project to NHibernate 3.3 and replaced the NHibernate and the Iesi.Collections References.
I kept NHibernate.ByteCode.Castle
I removed the line
<property name="proxyfactory.factory_class">NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle</property> from my application config.
Now I get the error NotSupportedException in the last line of the following code:
NHibernate.Cfg.Configuration cfg = new NHibernate.Cfg.Configuration();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
sessionFactory = cfg.BuildSessionFactory();
I googled a lot but I don't have a clue what's wrong. And ideas? Thanks!
my config:
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="dialect">NHibernate.Dialect.PostgreSQLDialect</property>
<property name="connection.driver_class">NHibernate.Driver.NpgsqlDriver</property>
<property name="connection.connection_string">Server=myserverip;Port=myport;database=my_test;User Id=my_user;Password=mypwd;CommandTimeout=1;</property>
<!--<property name="proxyfactory.factory_class">NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle</property>-->
<property name="command_timeout">0</property>
</session-factory>
Just add this line to your xml config
<property name="hbm2ddl.keywords">none</property>
More details described here:
C# / Postgres / FluentNHibernate : configuring npgsql throws NotSupportedException

Need access to table with string based primary key in nHibernate

I am trying to map a SQL Server database with nHibernate that is full of tables with varchar primary keys that are generated by external software and I need update/read (no insert) access.
I cannot find a way to get past the following error:
XXXX.Tests.GMCRepository_Fixture.Can_get_existing_GMC_by_parameter'
failed: NHibernate.MappingException :
XXXX.Domain.Mappings.GMC2.hbm.xml(4,6): XML validation error: The element 'class' in namespace 'urn:nhibernate-mapping-2.2' has invalid child element 'property' in namespace 'urn:nhibernate-mapping-2.2'. List of possible elements expected: 'meta, subselect, cache, synchronize, comment, tuplizer, id, composite-id' in namespace 'urn:nhibernate- mapping-2.2'.
Research has suggested this error is relating to there not being a valid primary key (id) defined.
Mapping XML looks like:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping assembly="XXXX.Domain" namespace="XXXX.Domain" xmlns="urn:nhibernate-mapping-2.2" schema="GM.dbo">
<class name="GMC2" table="C2" lazy="true" >
<property name="PARAMETER">
<column name="PARAMETER" sql-type="varchar" not-null="true" />
</property>
...
<id name="Recid">
<column name="recid" sql-type="varchar" not-null="true" />
</id>
</class>
</hibernate-mapping>
Thanks for your help!
I believe that the convention is to have the ID mapping as the first thing under the class declaration.
Also as part of the Id mapping you need to specify the Generator of the ID. In your case I think you will need the assigned generator added to your ID mapping. Your class mapping will look something like this.
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping assembly="XXXXCRMAPI.Domain" namespace="XXXXCRMAPI.Domain" xmlns="urn:nhibernate-mapping-2.2" schema="GoldMine.dbo">
<class name="GMContact2" table="CONTACT2" lazy="true" >
<id name="Recid">
<generator type="assigned" />
<column name="recid" sql-type="varchar" not-null="true" />
</id>
<property name="Accountno">
<column name="ACCOUNTNO" sql-type="varchar" not-null="true" />
</property>
...
</class>
</hibernate-mapping>

Unit testing NHibernate Postgresql with SQLite. Sequence generator problem

Can Sqlite NHibernate id generator be made compatible with Postgresql? I'm planning to unit test my NHibernate Postgresql project based on this http://ayende.com/Blog/archive/2009/04/28/nhibernate-unit-testing.aspx
If there is no compatible id generator, is there a way to signal NHibernate to ignore id generator when it is using different dialect?
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true" assembly="RuntimeNhibernate" namespace="RuntimeNhibernate" >
<class name="Blog" table="blog">
<id name="BlogId" column="blog_id">
<!-- can this be ignored when using different dialect.. -->
<generator class="sequence">
<param name="sequence">blog_id_seq</param>
</generator>
<!-- ...can this -->
</id>
<property name="AllowsComments" column="allows_comments"/>
<property name="CreatedAt" column="created_at"/>
<property name="Subtitle" column="subtitle"/>
<property name="Title" column="title"/>
</class>
</hibernate-mapping>
Error when using Sqlite dialect on Postgresql-specific mapping:
NHibernate.MappingException: could not instantiate id generator: sequence --->
NHibernate.MappingException: Dialect does not support sequences
My suggestion is that you use a DB-agnostic generator, like HiLo.

retrieve PK of mapped table with NHibernate

just started out with NHIbernate and have one question, probably a bit of a stupi one! ;-)
I have 2 tables, Email and Attachment, an email can have zero or more attachments. so I created a hbm file like this:
<set name="Attachments" table="Attachments">
<key column="EmailId" foreign-key="fk_Attachments_Emails"/>
<composite-element class="Foo.Emails.Attachment, Foo.Emails">
<!-- PROBLEM HERE!!! -->
<property name="Id" column="Id" type="long" />
<!-- END PROBLEM -->
<property name="Name" column="Name" type="String" length="50"/>
<property name="Mime" column="MimeType" type="String" length="50"/>
<property name="Size" column="Size" type="long" />
<property name="FilePath" column="FilePath" type="String" length="256"/>
<property name="Parsed" column="Parsed" type="Boolean" />
</composite-element>
</set>
As I want to be able to search for the attachments by PK (the Id column in the set) I included it, but now everytime I try to save an email with attachments I get an error from the db as Nhibernate tries to insert a value into the PK, which my db naturally wont allow.
So, my question is, can I extract the pk for the Attqachment table but stop Nhiberntate from writing it when inserting a an email/attachment? Should I swap to another container like ?? if so wold you be abler to provide an example as I struggling to find a one that I understand!
THanks for your help!
Perhaps a more practical example? Where you have an object structure like this:
Email
--EmailId
--EmailProperty1
--AttachmentCollection
Attachment
--AttachmentId
--ParentEmail
--AttachmentProperty1
mapped to a table structure like this (not how i'd name it, but it's for example):
email
--emailId int PK, identity
--emailProp1 varchar(50)
emailattachment
--attachmentId int PK, identity
--emailId int, FK to email table
--attachmentProp1 varchar(50)
<hibernate-mapping>
<class name="Email" table="email">
<id name="EmailId">
<!-- this tells NHibernate to use DB to generate id -->
<generator class="native"/>
</id>
<property name="EmailProperty1" column="emailProp1"/>
<bag name="AttachmentCollection" lazy="true" inverse="true">
<key column="emailId"/>
<one-to-many class="Foo.Emails.Attachment, Foo.Emails"/>
</bag>
</class>
<class name="Attachment" table="emailattachment">
<id name="AttachmentId">
<generator class="native"/>
</id>
<property="AttachmentProperty1" column="attachmentProp1"/>
<many-to-one name="ParentEmail" class="Foo.Emails.Email, Foo.Emails" lazy="proxy" column="emailId">
</class>
</hibernate-mapping>
In this map, you'd get the bi-directional relationship, and that generator tag is telling nhibernate that objects with a null Id property (you can also specify another "unsaved-value"), then you're inserting the object, else updating. Should fix your current problem.
Couple other things: examine closely what kind of containers you need to use when mapping (bag vs. set vs. list). There's an excellent writeup in hibernatingrhino's NHibernateFAQ.
Also, since you're new to NHibernate, I very, very greatly recommend the summer of nhibernate screencasts. The best tool I've found so far for learning.
I think you want an bi-directional relationship. This way you can navigate the association both ways. This includes generated keys... Here is an example:
<class name="Order" table="ORDERHEADER" lazy="false" >
<id name="OrderId" column="ORDERID" type="int">
<generator class="sequence">
<param name="sequence">"ORDERID_SEQ"</param>
</generator>
</id>
<property name="OrderType" column="ORDERTYPE" type="Int16"/>
<bag name="OrderDetail" table="ORDERDETAIL" lazy="false" inverse="true">
<key column="OrderId"/>
<one-to-many class="OrderDetail" />
</bag>
<class name="OrderDetail" table="ORDERDETAIL" lazy="false">
<id name="OrderDetailId" column="ORDERDETAILID" type="int">
<generator class="sequence">
<param name="sequence">"ORDERDTLID_SEQ"</param>
</generator>
</id>
<property name="OrderId" column="ORDERID" type="Int32"/>
<property name="ItemNumber" column="ITEMNUMBER" type="Int32"/>
<property name="OrderQuantity" column="ORDERQUANTITY" type="Int32"/>
<many-to-one name="Order" class="Order" column="OrderId" />

Categories