NHibernate stored procedure problem - nhibernate

I'm having a hard time trying to get my stored procedure works with NHibernate. The data returned from the SP does not correspond to any database table.
This is my mapping file:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="DomainModel" namespace="DomainModel.Entities">
<sql-query name="DoSomething">
<return class="SomeClass">
<return-property name="ID" column="ID"/>
</return>
exec [dbo].[sp_doSomething]
</sql-query>
</hibernate-mapping>
Here is my domain class:
namespace DomainModel.Entities
{
public class SomeClass
{
public SomeClass()
{
}
public virtual Guid ID
{
get;
set;
}
}
}
When I run the code, it fails with
Exception Details: NHibernate.HibernateException: Errors in named queries: {DoSomething}
at line 80
Line 78: config.Configure(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "NHibernate.config"));
Line 79:
Line 80: g_sessionFactory = config.BuildSessionFactory();
When I debug into NHibernate code, it seems that SomeClass is not added to the persister dictionary because there isn't a class mapping (only sql-query) defined in hbm.xml. And later on in CheckNamedQueries function, it is not able to find the persistor for SomeClass.
I've checked all the obvious things (e.g. make hbm as an embedded resource) and my code isn't too much different from other samples I found on the web, but somehow I just can't get it working. Any idea how I can resolve this issue?

Well, where is your class mapping for SomeClass?
You still need to map it. Read http://nhibernate.info/doc/nh/en/index.html#querysql-load.

Look at using a class mapping with a subselect block. I found this in the Java documentation but maybe it will work for .Net too.
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/mapping.html (scroll down to section 5.1.3)

Related

NHibernate not calling SQL Server

This method gets called.
public IList<MyStuff> GetMyStuff(Int64 MyStuffId)
{
ICriteria criteria = NHibernateSessionManager.Instance.GetSession().CreateCriteria(typeof(MyStuff));
criteria.Add(Expression.Eq("x", MyStuff));
return criteria.List<MyStuff>();
}
But if I profile SQL Server, I can see that NHibernate doesn't try to access the server.
No errors are thrown. It is just the criteria.List() simply returns 0 rows.
MyStuff is a class
public class MyStuff {
public virtual int Id { get; set; }
public virtual int x { get; set; }
... more attributes ....
public override int GetHashCode() {
return (GetType().FullName + "|" + Id.ToString()).GetHashCode();
}
}
And MyStuff is a HBM mapping:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="false" assembly="MyStuff" namespace="My.Stuff" default-lazy="false">
<class name ="MyStuff" table="dbo.viewMyStuff" dynamic-update="false" lazy="false">
<cache usage="read-only"/>
<id name="Id" column="Id" type="int">
<generator class="native" />
</id>
<property name="x" />
.... other properties
</class>
</hibernate-mapping>
The following works just:
select * from viewMyStuff
NHibernate does just fine with other classes/views in the same project.
In fact if I intentionally typo the "table" in the HBM file to "XviewXMyStuffX" NHibernate doesn't have any problem with the typo. Why is NHibernate simply ignoring the expected attempt to access my database view?
I turns out that the view treats the attribute "x" as a string. But in nHibernate I define it as a Int64. These type differences much be causing the criteria to fail. But without any reported error?
Double check that your query really tries to use the exact class you intenden, and that the mapping also applies to exactly the same class. Beware of classes with same name in different namespace or assembly, for instance. One cause of this type of issue is if you attempt to query for a class that is in fact not mapped in NHibernate - then NHibernate will return en empty result, and not an error.
Oh, and have you tried without the cache-element to rule that out?

Can not execute stored procedure with nHibernate

Firstly, I'm sorry for asking this question AGAIN when there are several resources that (theoretically)
explain it. I've listed the references I used at the bottom of this question, hopefully they will
help someone else if nothing else.
I am trying to execute a simple stored proc on an oracle 11 database. My intent is to create
a List{T} object from data returned via a SYS_REFCURSOR.
I get this error message as soon as I try to to create an nhibernate session object:
{"Errors in named queries: {GET_COLLATERAL}"}
Here is my mapping. The namespace, schema, assembly, query name are spelled correctly.
The file is named GetCollateral.hbm.xml and is marked as an embedded resource.
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Poolman" namespace="Poolman.Entities" schema="poolman_own">
<sql-query name="GET_COLLATERAL" callable="true">
<return class="Poolman.Entities.IDNamePair">
<return-property name="ID" column="sort_order"></return-property>
<return-property name="Name" column="collateral"></return-property>
</return>
{GET_COLLATERAL(?)}
</sql-query>
</hibernate-mapping>
After quite a bit of troubleshooting I managed to get a session object to be created
by removeing the return element from the mapping as shown below. Apparently there is something wrong with it
but I don't know what.
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Poolman" namespace="Poolman.Entities" schema="poolman_own">
<sql-query name="GET_COLLATERAL" callable="true">
{GET_COLLATERAL(?)}
</sql-query>
</hibernate-mapping>
I don't expect to get a result set back with no return mapping, but using the mapping above allows nhibernate to create its session obect and to try to execute the query. However, nHibernate cannot get it's parameters right. I get this error message:
{"Expected positional parameter count: 1, actual parameters: [] [{GET_COLLATERAL(?)}]"}
I've tried:
CALL GET_COLLATERAL()
BEGIN GET_COLLATERAL(); END;
The above wrapped in CDATA
Here is my stored proc:
create or replace
PROCEDURE GET_COLLATERAL(p_cursor OUT SYS_REFCURSOR)
IS
BEGIN
OPEN p_cursor for
SELECT collateral, sort_order
FROM
(
-- Long query omitted. The query executes when pasted into a command window.
) ORDER BY sort_order ;
END;
Here is my entity class. This class does not map to any one table but I tried to create a mapping for it anyhow.
namespace Poolman.Entities
{
public class IDNamePair
{
public virtual int ID { get; set; }
public virtual string Name { get; set; }
}
}
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping assembly="Poolman"
namespace="Poolman.Entities"
schema="poolman_own"
xmlns="urn:nhibernate-mapping-2.2">
<class name="IDNamePair" table="x">
<id></id>
<property name="ID" column="sort_order"/>
<property name="Name" column="collateral"/>
</class>
</hibernate-mapping>
Here is the code I'm using to call the query:
public List<Entities.IDNamePair> GetCollateral()
{
IQuery query = (IQuery)Session.GetNamedQuery("GET_COLLATERAL");
List<Entities.IDNamePair> list = new List<Entities.IDNamePair>();
System.Collections.IList result = query.List();
list = result.OfType<Entities.IDNamePair>().ToList();
return list;
}
I really appreciate any help with this. I'm stuck.
Here are links to other resources I've found, none can help me however:
Sorry stackoverflow only allows me to post two links:
Oracle stored procedures, SYS_REFCURSOR and NHibernate
http://www.techonthenet.com/oracle/questions/cursor1.php
Maybe two considerations could be done for this problem:
First, the Stored Procedure which has no input parameters, does not require to be called with parameters, so as this questions comment says calling sp with out ref cursor call the SP in this way { call GET_COLLATERAL }
Second, to use a "not mapped" class as result set, you should instruct nhibernate about that "not mapped" class, so try to add <import class="FullClassName" rename="ClassNameMayBeRenamed"/> at top of the mapping file
So this could be a mapping for this SP:
....
<import class="Poolman.Entities.IDNamePair" />
....
<sql-query name="GET_COLLATERAL" callable="true">
<return class="Poolman.Entities.IDNamePair">
<return-property name="ID" column="sort_order"></return-property>
<return-property name="Name" column="collateral"></return-property>
</return>
{ call GET_COLLATERAL}
</sql-query>
The calling code could be a simple code to call a SP through NHibernate..
I hope this could be your solution. Please let me know if I'm wrong
Regards

How to find unmapped properties in a NHibernate mapped class?

I just had a NHibernate related problem where I forgot to map one property of a class.
A very simplified example:
public class MyClass
{
public virtual int ID { get; set; }
public virtual string SomeText { get; set; }
public virtual int SomeNumber { get; set; }
}
...and the mapping file:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="MyAssembly"
namespace="MyAssembly.MyNamespace">
<class name="MyClass" table="SomeTable">
<property name="ID" />
<property name="SomeText" />
</class>
</hibernate-mapping>
In this simple example, you can see the problem at once:
there is a property named "SomeNumber" in the class, but not in the mapping file.
So NHibernate will not map it and it will always be zero.
The real class had a lot more properties, so the problem was not as easy to see and it took me quite some time to figure out why SomeNumber always returned zero even though I was 100% sure that the value in the database was != zero.
So, here is my question:
Is there some simple way to find this out via NHibernate?
Like a compiler warning when a class is mapped, but some of its properties are not.
Or some query that I can run that shows me unmapped properties in mapped classes...you get the idea.
(Plus, it would be nice if I could exclude some legacy columns that I really don't want mapped.)
EDIT:
Okay, I looked at everything you proposed and decided to go with the meta-data API...that looks the easiest to understand for me.
Now that I know what to search for, I found some examples which helped me to get started.
So far, I have this:
Type type = typeof(MyClass);
IClassMetadata meta = MySessionFactory.GetClassMetadata(type);
PropertyInfo[] infos = type.GetProperties();
foreach (PropertyInfo info in infos)
{
if (meta.PropertyNames.Contains(info.Name))
{
Console.WriteLine("{0} is mapped!", info.Name);
}
else
{
Console.WriteLine("{0} is not mapped!", info.Name);
}
}
It nearly works, except one thing:
IClassMetadata.PropertyNames returns the names of all the properties except the ID.
To get the ID, I have to use IClassMetadata.IdentifierPropertyName.
Yes, I could save .PropertyNames in a new array, add .IdentifierPropertyName to it and search that array.
But this looks strange to me.
Is there no better way to get all mapped properties including the ID?
You could use the NHibernate meta-data API to find the mapped properties, and reflection to find all the properties.
Edit No, there isn't any other way list all the properties including the id. It isn't that hard to use:
foreach (PropertyInfo info in infos)
{
if (meta.PropertyNames.Contains(info.Name) || info.Name = meta.IdentifierPropertyName)
{
Console.WriteLine("{0} is mapped!", info.Name);
}
else
{
Console.WriteLine("{0} is not mapped!", info.Name);
}
}
There are two tools I'm aware of that can help with this:
Fluent NHibernate persistence specification testing
Nhibernate Ghostbuster
but they don't specifically address the problem you had with an unmapped property. The best solution is to write good unit tests that ensure that the properties you want to persist are persisted correctly. It's tedious but necessary.

Fluent NHibernate and Stored Procedures

I have a basic Customer/Order/OrderItem/Product object graph. Customer has Many Orders, Order has Many Order Items, Product has many Order Items. These are successfully mapped using FNH.
I've hit a snag with configuring a stored procedure & fluent-nhibernate. There is not a native way to map stored procedures in fluent-hibernate FNH (version 1.0 RTM). There was a solution here about adding parts to class mappings but the AddPart call has been taken out of the release of FNH.
The stored procedure is simple:
CREATE PROCEDURE [dbo].[OrderCountByCustomer]
AS
BEGIN
SET NOCOUNT ON;
SELECT
c.name as [Customer.Name],
CAST(count(o.id) as NVARCHAR) as [Customer.OrderCount]
FROM customer c
LEFT OUTER JOIN [order] o
ON o.customer_id = c.id
GROUP BY c.name
END
There's a CustomerOrderSummary.hbm.xml in
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NVAble.Orders.Core" namespace="NVAble.Orders.Core">
<sql-query name="OrderSummary">
<return class="CustomerOrderSummary">
<return-property column="Customer.Name" name="CustomerName" />
<return-property column="Customer.OrderCount" name="OrderCount" />
</return>
EXEC [OrderCountByCustomer]
</sql-query>
</hibernate-mapping>
Here is the CustomerOrderSummary class def:
namespace NVAble.Orders.Core
{
public class CustomerOrderSummary
{
virtual public string CustomerName { get; set; }
virtual public string OrderCount { get; set; }
public override string ToString()
{
return string.Format("{0} {1}", CustomerName, OrderCount);
}
}
}
However, when try to start a NH session i get error in named query OrderSummary with no other details.
I'm probably missing something really simple that maps the CustomerOrderSummary class to the procedure, I don't know. That domain object obviously doesn't map directly to a table in the data base so I'm unsure if having a normal <class /> HBM mapping would work?
Thanks in advance!
Ok, so after a bit more investigation. I needed a mapping for the Domain Class as well as a named query hbm.xml file.
In my configure class i have
config.Mappings(x =>
{
x.FluentMappings.AddFromAssemblyOf<CustomerMapping>().ExportTo(schemaPath);
x.HbmMappings.AddFromAssemblyOf<CustomerOrderSummary>();
});
Only downside is that I need to manually create the xml mapping for the stored procedure, I can't use FNH at the current time

Nhibernate: QuerySyntaxException: 'Class' is not mapped

I have the following class:
public class MyClass
{
private List<long> _myList = new List<long>();
public virtual string MyID { get; set; }
public virtual string MyData
{
get
{
return SomeStaticClass.Serialize(_myList);
}
set
{
_myList = SomeStaticClass.Deserialize<List<long>>(value);
}
}
public virtual List<long> MyList
{
get { return _myList; }
}
}
And the following mapping file:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="MyNamespace"
namespace="MyNamespace">
<class name="MyNamespace.MyClass" table="MY_TABLE">
<id name="MyID" column="MY_ID" type="System.String">
<generator class="assigned"></generator>
</id>
<property name="MyData" column="MY_DATA"></property>
</class>
</hibernate-mapping>
When I try to run the following line:
session.Delete("From MyClass m");
I am getting a QuerySyntaxException with the message "MyClass is not mapped [From MyClass s]".
When I change the name of the "MyID" field to "ID" in the mapping file, the exception becomes
NHibernate.PropertyNotFoundException: Could not find a getter for property 'ID' in class 'MyNamespace.MyClass'.
so I am assuming it can find the mapping file. I made sure that the mapping file is an embedded resource, checked and dobule checked the namespace and class names in the mapping file. What may cause the error? I think it may relate to the MyList property which is not mapped but I am not sure since I am using non-mapped properties on my other classes without a problem.
EDIT: I tried overriding this class, with a class which has no "MyData" property and redefining "MyList" property as string. I am still receiving the same error for my overridden class.
EDIT 2: Tried with a very simple class with the same property names with same return types and only simple get; set; blocks. I still get the same error. I am almost sure that nhibernate can see my mapping files because if I change the name of a single property, it gives me PropertyNotFound instead of "class in not mapped".
How are you loading the hbms? If they are resources, make sure you've actually set the files to be embedded resources in Visual Studio
In case of mapping
<class name="MyClass" table="MY_TABLE">
you should use, for example:
session.CreateQuery("from MyClass")
but not:
session.CreateQuery("from MY_TABLE")
what about if you use
session.Delete("From MyNamespace.MyClass m");
I was just looking at the HQL reference and noticed in their cat example they use fully qualified objects, i.e. Eg.Cat.
You should set the related *.hbm.xml as Embedded Resource.
Make sure your "Build Action of the file" is "Embedded Resource".
I had this problem. I forgot to put hbm in the name of mapping XML files.
it seems a bit strange you are specifying the namespace twice in the mapping file. I would try just specifying the name attribute as just "MyClass" instead of "MyNamespace.MyClass" so it would be
<class name="MyClass" table="MY_TABLE">
I had a similar problem like this. Basically, I included a new project into the solution and I did not map the namespace in the hibernate.cfg.xml file.