I love NHibernate and I love Fluent NHibernate. Fluent NHibernate allows you to use NHibernate without the XML configuration files that would normally be required by NHibernate. In fact, by using the AutoMap feature of Fluent NHibernate, you can use NHibernate without writing ANY additional lines of code beyond adding virtual to your POCO classes. That sounds great.
Sometimes, however, NHibernate can give you error messages that aren't as intuitive as they could be. This is a small complaint because we software developers can always figure out how to do things....right? So you have created your classes, set up Fluent NHibernate and tried to save something only to find that NHibernate is not saving your entity. You try and try, but NHibernate will not save your entity. You look at the error message and you see the following:
Unexpected row count: 0; expected: 1
That message doesn't look good. Why won't NHibernate save? Whatever could the NHibernate problem be? Well I don't know all of the reasons that this error message might occur, but I do know one reason that I'm going to tell you about.
If you are using GUIDs or INTs as the primary key on your entity, NHibernate needs to see that entity id as empty so that it will know that the item you are saving is new. You will get the error shown above if you try to add the GUID or INT yourself. I know. I know. This is kind of counter to how you do things in Entity Framework, but isn't NHibernate smart? It can and will generate the id for you so you can sit back and relax (well you can't really relax, but NHibernate will create the id for you). To solve the problem, do not try to assign an int or Guid to your id. When NHibernate sees that the value is empty, NHibernate will recognize this to be a new item and perform a database Insert instead of an Update.
Wasn't that simple. I just told you to do nothing and I solved your problem.
Hope this saves you some time!
Smooches,
Kila
Problem:
This blog is for all Microsoft & .net lovers who may find themselves in need of help or information once in a while. We all have questions and we all need to know more than we know right now. When I come across things that I think may be useful, I post it. When I have something to say that I think is important, which is everything, I post it. All of my C#, ASP.NET, VB, AJAX & programming friends around the world are welcome to the info in my blog - Ramblings Of A Crazy DotNet Woman!
Showing posts with label NHibernate. Show all posts
Showing posts with label NHibernate. Show all posts
Saturday, August 14, 2010
Understanding Fluent NHibernate - The entity doesn't have an Id mapped. Use the Id method to map your identity property. For example: Id(x => x.Id)
The entity 'YourEntityName' doesn't have an Id mapped. Use the Id method to map your identity property. For example: Id(x => x.Id). Don't you just love Fluent NHibernate error messages?
So you have set up your database, got your tables together, created some classes and tried to use Fluent NHibernate to map and......you get the following - The entity 'YourEntityName' doesn't have an Id mapped. Use the Id method to map your identity property. For example: Id(x => x.Id). It seems like a straightforward error right? It looks like Fluent NHibernate is looking for an Id and you don't have it. But you think to yourself, "Self...you know you put that YourPropertyNameId in there. What could be going on?"
Well the truth is that the error is not as verbose as it seems. It means EXACTLY what it says. Let us say for a moment that you have a table named Projects. This Projects table has a primary key column called ProjectId. You are using Fluent NHibernate and NHibernate in ASP.NET MVC to automagically generate NHibernate mappings so that you don't have to do it by hand. Well, Fluent NHibernate expects to see that primary key column name displayed as Id NOT as ProjectId! What???? That is correct - Fluent NHibernate can't be expected to just "know" what everyone using it will name the primary key - soooo when you are using the AUTOMAPPING FEATURE that allows you to generate mapping files WITHOUT typing a line of code, you have to give those identity columns a nice GENERIC name of Id. Using something like {get; private set;} is not enough. If that naming convention doesn't work for you, you can do a few things. You can override the IsId feature. The override below, which would be placed in the configuration file, specifies that anything with the EntityNameId is the Id.
Now, that is the way to do it IF you are using configuration files. I don't.
I should because that was the suggested upgrade from Fluent NHibernate 1.0 to 1.1,
but I don't because the creator in his infinite wisdom still allows me to do it like this.
For
Fluent NHibernate can make your life sooo much easier if you are using NHibernate, but you have to read the automapping area on the Fluent NHibernate Wiki if you really want to be able to use it to its fullest potential. READ IT HERE :-). No one likes to spend precious minutes/hours looking for why you get small issues like this, but if you read the wiki maybe you won't have to. I promise you that it won't hurt!
Smooches,
Kila
Problem:
When using Fluent NHibernate with the AutoMap feature, you get the following error - The entity 'YourEntityName' doesn't have an Id mapped. Use the Id method to map your identity property.
Solution:
Rename your primary key from whatever it was to Id or create the ClassMap files by hand and designate the column to be used as your primary key in that class. Don't forget to change your Fluent.Configure .Mappings area to something like this - .Mappings(x => x.FluentMappings.AddFromAssemblyOf() - so that you remove the Automap from the Mappings attribute.
You can also designate your column as a primary key by using the hbm.xml file structure, but that is too much work and you don't have type checking to make sure you didn't screw something up AND you defeat the purpose of Fluent NHibernate. Don't defeat the purpose people - just don't do it!
So you have set up your database, got your tables together, created some classes and tried to use Fluent NHibernate to map and......you get the following - The entity 'YourEntityName' doesn't have an Id mapped. Use the Id method to map your identity property. For example: Id(x => x.Id). It seems like a straightforward error right? It looks like Fluent NHibernate is looking for an Id and you don't have it. But you think to yourself, "Self...you know you put that YourPropertyNameId in there. What could be going on?"
Well the truth is that the error is not as verbose as it seems. It means EXACTLY what it says. Let us say for a moment that you have a table named Projects. This Projects table has a primary key column called ProjectId. You are using Fluent NHibernate and NHibernate in ASP.NET MVC to automagically generate NHibernate mappings so that you don't have to do it by hand. Well, Fluent NHibernate expects to see that primary key column name displayed as Id NOT as ProjectId! What???? That is correct - Fluent NHibernate can't be expected to just "know" what everyone using it will name the primary key - soooo when you are using the AUTOMAPPING FEATURE that allows you to generate mapping files WITHOUT typing a line of code, you have to give those identity columns a nice GENERIC name of Id. Using something like {get; private set;} is not enough. If that naming convention doesn't work for you, you can do a few things. You can override the IsId feature. The override below, which would be placed in the configuration file, specifies that anything with the EntityNameId is the Id.
public override bool IsId(Member member)
{
return member.Name == member.DeclaringType.Name + "Id";
}
Now, that is the way to do it IF you are using configuration files. I don't.
I should because that was the suggested upgrade from Fluent NHibernate 1.0 to 1.1,
but I don't because the creator in his infinite wisdom still allows me to do it like this.
public ISessionFactory GetSessionFactory()
{
var connectionString = ConfigurationManager
.ConnectionStrings["YOUR_CONNECTION
_STRING_NAME_AS_DEFINED_
IN_YOUR_WEB_CONFIG_FILE"]
.ConnectionString;
//Fluent NHibernate configurartion
var sessionFactory = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005
.ConnectionString(x => x
.Is(connectionString)))
.Mappings(m => m.AutoMappings
.Add(AutoMap.AssemblyOf<YOUR_ENTITY_NAME>()
.Setup(cfg =>
{cfg.FindIdentity = member => member
.Name == member
.DeclaringType.Name + "Id";}
)))
.BuildSessionFactory();
return sessionFactory;
}
For
YOUR_ENTITY_NAME
shown above, you can select ANY class in the directory that you want. Fluent NHibernate just uses that class to tell where ALL of your classes are so don't worry about which one to specify there. You can also use Fluent NHibernate to generate the actual mapping classes decorated with ClassMap and then make any adjustments . However, that means that you can't use the Automapping magical save-me-some-work feature.
Fluent NHibernate can make your life sooo much easier if you are using NHibernate, but you have to read the automapping area on the Fluent NHibernate Wiki if you really want to be able to use it to its fullest potential. READ IT HERE :-). No one likes to spend precious minutes/hours looking for why you get small issues like this, but if you read the wiki maybe you won't have to. I promise you that it won't hurt!
Smooches,
Kila
Problem:
When using Fluent NHibernate with the AutoMap feature, you get the following error - The entity 'YourEntityName' doesn't have an Id mapped. Use the Id method to map your identity property.
Solution:
Rename your primary key from whatever it was to Id or create the ClassMap files by hand and designate the column to be used as your primary key in that class. Don't forget to change your Fluent.Configure .Mappings area to something like this - .Mappings(x => x.FluentMappings.AddFromAssemblyOf
You can also designate your column as a primary key by using the hbm.xml file structure, but that is too much work and you don't have type checking to make sure you didn't screw something up AND you defeat the purpose of Fluent NHibernate. Don't defeat the purpose people - just don't do it!
Monday, August 9, 2010
Use StructureMap To Create And Dispose Of NHibernate Sessions
If you are using StructureMap to manage sessions for NHibernate, you may have encountered situations where you would like to dispose of those sessions in a clean and efficient manner. You could create your own code to manage this (good luck with that) or you could use StructureMap to handle that too.
In the current version of StructureMap, you can use the following code placed in the Application_EndRequest event of your Global.asax file.
ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
If you are using an old release of StructureMap, you can use the following code placed in the Application_EndRequest event of your Global.asax file.
HttpContextBuildPolicy.DisposeAndClearAll();
Either way, you can use StructureMap to manage the clean up of your sessions in NHibernate. I hope this knowledge makes your life easier!
Smooches,
Kila
In the current version of StructureMap, you can use the following code placed in the Application_EndRequest event of your Global.asax file.
ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
If you are using an old release of StructureMap, you can use the following code placed in the Application_EndRequest event of your Global.asax file.
HttpContextBuildPolicy.DisposeAndClearAll();
Either way, you can use StructureMap to manage the clean up of your sessions in NHibernate. I hope this knowledge makes your life easier!
Smooches,
Kila
Subscribe to:
Posts (Atom)