Enum to integer mapping causing updates on every flush - nhibernate

I am trying to map an enum property (instance of System.DayOfWeek) in my model to an integer database field.
Other enum properties in the model should be mapped to strings, so I don't wish to define a convention.
I understand that this should be possible using a fluent mapping like:
Map(x => x.DayOfWeek).CustomType<int>();
and indeed, at first glance this appears to be working.
However, I noticed that instances of entities with properties mapped in this way are being updated every time the session was flushed, even though no amendments have been made to them.
To find out what is causing this flush, I set up an IPreUpdateEventListener, and inspected the OldState and State of the entity.
See the attached image. In the OldState, the relevant object is an int, whereas in State it is a DayOfWeek.
If I use an HBM XML mapping with no type attribute specified, this issue doesn't arise.
So...
Is this a bug or shortcoming in the GenericEnumMapper?
Is there any way of telling the FNH mapping not to specify any type attribute on the generated HBM?
If not, can I specify the default type that NH uses for enums (and what is that)?

If you use my enum convention you don't have that problem.
public class EnumConvention : IPropertyConvention, IPropertyConventionAcceptance
{
public void Apply(IPropertyInstance instance)
{
instance.CustomType(instance.Property.PropertyType);
}
public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
{
criteria.Expect(x => x.Property.PropertyType == typeof(AddressType) ||
x.Property.PropertyType == typeof(Status) ||
x.Property.PropertyType == typeof(DayOfWeek));
}
}
You can then map your property like regular:
Map(x => x.DayOfWeek);
EDIT : Updated the convention to pick specific enums to use for the int conversion. All enums that are not checked here would be mapped as string. You might have to experiment a little with what to actually test against. I am unsure if the propertytype will do it directly.

I know I'm late to the party - it's been two years since the question. But since I've stumbled upon this, I might just add solved the problem for me:
Map(x => x.DayOfWeek).CustomType<enumType>();
It did the trick for me: it stopped updating every time.
Source: https://groups.google.com/forum/#!searchin/fluent-nhibernate/enum/fluent-nhibernate/bBXlDRvphDw/AFnYs9ei7O0J

One workaround that I use is to have an int backing field and letting NHibernate use that for mapping.
Whenever NHibernate has to do a cast to compare the new value with the old one - it is always marked as dirty - causing the flush.

Simple way that worked for me was to change mapping's custom type from int to PersistentEnumType. Make sure to declare a generic version to make your life easier:
public class PersistentEnumType<T> : PersistentEnumType {
public PersistentEnumType() : base(typeof(T)) {}
}
Then use
Map(x => x.DayOfWeek)
.CustomType<PersistentEnumType<System.DayOfWeek>>();
This does not require changes to your entities, only mappings, and can be applied on a per-property basis.
See more here.

It depends on if you need to have DayOfWeek specifically as an integer.
If you're casting as part of the mapping, equality will always fail, and the property will be marked as dirty.
I'd probably map:
Map(x => x.DayOfWeek).CustomType();
and create a read only property that presents the DayOfWeek value as an integer if it's really required. Regardless, mapping as the actual type should work and prevent false-dirty.

You might consider an alternate approach; I have found the usage of Fabio Maulo's well known instance types to be invaluable for such uses. The benefit of these is immediately apparent any time you find yourself trying to extend what a basic enum can do (eg. providing a localized description, etc.)

Related

NHibernate property value null but member value not null

I have a object that has a property that is a reference to another type and uses a camel case private member variable as a backing. When I run my application the property value is being returned as null but if I debug and inspect the field it is not null. Here is what the property looks like:
public virtual FileType FileType
{
get { return this.fileType; }
set { this.fileType = value; }
}
I am using Fluent NHibernate to do the mapping and this is what the mapping looks like:
this.References<FileType>(x => x.FileType)
.Column("FileTypeID")
.LazyLoad()
.Cascade.SaveUpdate()
.Access.CamelCaseField();
I have other object with the exact same layout as this one and they work but for some reason this particular object property always return null. Has anyone ever seen anything like this and would be able to give me some idea how to fix it?
I had the same issue, out of curiosity I upgraded NHibernate from version 3.3.1.4000 to NHibernate 3.4.1.4000 as I thought it had to be a bug in either NHibernate or Fluent and it went away so assume it was a bug in NHibernate. Just for extra information, I am targeting FluentNhibernate version 1.4.0.0.

domain design with nhibernate

In my domain I have something called Project which basically holds a lot of simple configuration propeties that describe what should happen when the project gets executed. When the Project gets executed it produces a huge amount of LogEntries. In my application I need to analyse these log entries for a given Project, so I need to be able to partially successively load a portion (time frame) of log entries from the database (Oracle). How would you model this relationship as DB tables and as objects?
I could have a Project table and ProjectLog table and have a foreign key to the primary key of Project and do the "same" thing at object level have class Project and a property
IEnumerable<LogEntry> LogEntries { get; }
and have NHibernate do all the mapping. But how would I design my ProjectRepository in this case? I could have a methods
void FillLog(Project projectToFill, DateTime start, DateTime end);
How can I tell NHibernate that it should not load the LogEntries until someone calls this method and how would I make NHibernate to load a specifc timeframe within that method?
I am pretty new to ORM, maybe that design is not optimal for NHibernate or in general? Maybe I shoul design it differently?
Instead of having a Project entity as an aggregate root, why not move the reference around and let LogEntry have a Product property and also act as an aggregate root.
public class LogEntry
{
public virtual Product Product { get; set; }
// ...other properties
}
public class Product
{
// remove the LogEntries property from Product
// public virtual IList<LogEntry> LogEntries { get; set; }
}
Now, since both of those entities are aggregate roots, you would have two different repositories: ProductRepository and LogEntryRepository. LogEntryRepository could have a method GetByProductAndTime:
IEnumerable<LogEntry> GetByProductAndTime(Project project, DateTime start, DateTime end);
The 'correct' way of loading partial / filtered / criteria-based lists under NHibernate is to use queries. There is lazy="extra" but it doesn't do what you want.
As you've already noted, that breaks the DDD model of Root Aggregate -> Children. I struggled with just this problem for an absolute age, because first of all I hated having what amounted to persistence concerns polluting my domain model, and I could never get the API surface to look 'right'. Filter methods on the owning entity class work but are far from pretty.
In the end I settled for extending my entity base class (all my entities inherit from it, which I know is slightly unfashionable these days but it does at least let me do this sort of thing consistently) with a protected method called Query<T>() that takes a LINQ expression defining the relationship and, under the hood in the repository, calls LINQ-to-NH and returns an IQueryable<T> that you can then query into as you require. I can then facade that call beneath a regular property.
The base class does this:
protected virtual IQueryable<TCollection> Query<TCollection>(Expression<Func<TCollection, bool>> selector)
where TCollection : class, IPersistent
{
return Repository.For<TCollection>().Where(selector);
}
(I should note here that my Repository implementation implements IQueryable<T> directly and then delegates the work down to the NH Session.Query<T>())
And the facading works like this:
public virtual IQueryable<Form> Forms
{
get
{
return Query<Form>(x => x.Account == this);
}
}
This defines the list relationship between Account and Form as the inverse of the actual mapped relationship (Form -> Account).
For 'infinite' collections - where there is a potentially unbounded number of objects in the set - this works OK, but it means you can't map the relationship directly in NHibernate and therefore can't use the property directly in NH queries, only indirectly.
What we really need is a replacement for NHibernate's generic bag, list and set implementations that knows how to use the LINQ provider to query into lists directly. One has been proposed as a patch (see https://nhibernate.jira.com/browse/NH-2319). As you can see the patch was not finished or accepted and from what I can see the proposer didn't re-package this as an extension - Diego Mijelshon is a user here on SO so perhaps he'll chime in... I have tested out his proposed code as a POC and it does work as advertised, but obviously it's not tested or guaranteed or necessarily complete, it might have side-effects, and without permission to use or publish it you couldn't use it anyway.
Until and unless the NH team get around to writing / accepting a patch that makes this happen, we'll have to keep resorting to workarounds. NH and DDD just have conflicting views of the world, here.

Readonly Strategies with Nhibernate and Fluent Nhibernate

I been reading nhibernate for beginners 3.0 and been reading about common mistakes(a few of them I been making)
I am wondering what are some strategies for making one or more records readonly. Right now I get all the rows back and loop through them making them readonly through session.Readonly().
I like in the book that they do with fluent
class EntityMap : ClassMap<Entity>
{
public EntityMap()
{
SchemaAction.None();
ReadOnly();
// Mappings
}
}
What I am not sure is what happens if I need these records to not be Readonly? To me this means I have to make this exact same mapping minus those 2 lines of code.
So I would like to do this and have ReadonlyEntityMap and EntityMap but I rather not have to duplicate all the settings twice.
Anyone have ideas on how do to this? Or better ideas for readonly?
Using ReadOnly() on your mapping will disable any updates back to the database when you modify the properties of the object.
If you want to apply some sort of ReadOnly and Writeable strategy I would suggest using a Fluent Convention and a marker interface or similar.
You can also apply ReadOnly() to a property if you want to disable writes on just that one property. I use that technique to avoid writing back to Computed Columns in SQL Server.
Something like this:
public interface IReadOnly{} //Mark entities with this interface
public class ReadOnlyConvention
: IClassConvention, IClassConventionAcceptance<IClassInspector>
{
public void Accept(IAcceptanceCriteria<IClassInspector> criteria)
{
criteria.Expect(x => x.EntityType Is IReadOnly);
}
public void Apply(IClassInstance instance)
{
instance.ReadOnly();
}
}
Update:
If you want to do you time conversion thing I would suggest creating an IUserType for your DateTime object which does the conversion to the user time without modifying the underlying data.
Date Time Support in NHibernate
Custom IUserType for DateTime
It depends on what you are trying to achieve. If you are trying to optimize memory consumption you should consider improving your session management strategy or using other performance improvement techniques. You can for example:
Clear the session that loaded your objects and it will release all the memory allocated by first level cache. The objects can later be reattached (Merged) to a new session if needed. This way you don't need objects to be readonly in the first place.
Evict some of the objects when you no longer need them. This will keep the other objects in the first level cache.
Use IStatelessSession which does not use 1st level cache at all.
Again, the answer depends on your application architecture.

Accept Interface into Collection (Covariance) troubles with nHibernate

I am using Fluent nHibernate for my persistence layer in an ASP.NET MVC application, and I have come across a bit of a quandry.
I have a situation where I need to use an abstraction to store objects into a collection, in this situation, an interface is the most logical choice if you are looking at a pure C# perspective.
Basically, an object (Item) can have Requirements. A requirement can be many things. In a native C# situation, I would merely accomplish this with the following code.
interface IRequirement
{
// methods and properties neccessary for evaluation
}
class Item
{
virtual int Id { get; set; }
virtual IList<IRequirement> Requirements { get; set; }
}
A crude example. This works fine in native C# - however because the objects have to be stored in a database, it becomes a bit more complicated than that. Each object that implements IRequirement could be a completely different kind of object. Since nHibernate (or any other ORM that I have discovered) cannot really understand how to serialize an interface, I cannot think of, for the life of me, how to approach this scenario. I mean, I understand the problem.
This makes no sense to the database/orm. I understand completely why, too.
class SomeKindOfObject
{
virtual int Id { get; set; }
// ... some other methods relative to this base type
}
class OneRequirement : SomeKindOfObject, IRequirement
{
virtual string Name { get; set; }
// some more methods and properties
}
class AnotherKindOfObject
{
virtual int Id { get; set; }
// ... more methods and properties, different from SomeKindOfObject
}
class AnotherRequirement : AnotherKindOfObject, IRequirement
{
// yet more methods and properties relative to AnotherKindOfObject's intentive hierarchy
}
class OneRequirementMap : ClassMap<OneRequirement>
{
// etc
Table("OneRequirement");
}
class AnotherRequirementMap : ClassMap<AnotherRequirement>
{
//
Table("OtherRequirements");
}
class ItemMap : ClassMap<Item>
{
// ... Now we have a problem.
Map( x => x.Requirements ) // does not compute...
// additional mapping
}
So, does anyone have any ideas? I cannot seem to use generics, either, so making a basic Requirement<T> type seems out. I mean the code works and runs, but the ORM cannot grasp it. I realize what I am asking here is probably impossible, but all I can do is ask.
I would also like to add, I do not have much experience with nHibernate, only Fluent nHibernate, but I have been made aware that both communities are very good and so I am tagging this as both. But my mapping at present is 100% 'fluent'.
Edit
I actually discovered Programming to interfaces while mapping with Fluent NHibernate that touches on this a bit, but I'm still not sure it is applicable to my scenario. Any help is appreciated.
UPDATE (02/02/2011)
I'm adding this update in response to some of the answers posted, as my results are ... a little awkward.
Taking the advice, and doing more research, I've designed a basic interface.
interface IRequirement
{
// ... Same as it always was
}
and now I establish my class mapping..
class IRequirementMap : ClassMap<IRequirement>
{
public IRequirementMap()
{
Id( x => x.Id );
UseUnionSubclassForInheritanceMapping();
Table("Requirements");
}
}
And then I map something that implements it. This is where it gets very freaky.
class ObjectThatImplementsRequirementMap : ClassMap<ObjectThatImplementsRequirement>
{
ObjectThatImplementsRequirementMap()
{
Id(x => x.Id); // Yes, I am base-class mapping it.
// other properties
Table("ObjectImplementingRequirement");
}
}
class AnotherObjectThatHasRequirementMap : ClassMap<AnotherObjectThatHasRequirement>
{
AnotherObjectThatHasRequirementMap ()
{
Id(x => x.Id); // Yes, I am base-class mapping it.
// other properties
Table("AnotheObjectImplementingRequirement");
}
}
This is not what people have suggested, but it was my first approach. Though I did it because I got some very freaky results. Results that really make no sense to me.
It Actually Works... Sort Of
Running the following code yields unanticipated results.
// setup ISession
// setup Transaction
var requirements = new <IRequirement>
{
new ObjectThatImplementsRequirement
{
// properties, etc..
},
new AnotherObjectThatHasRequirement
{
// other properties.
}
}
// add to session.
// commit transaction.
// close writing block.
// setup new session
// setup new transaction
var requireables = session.Query<IRequirable>();
foreach(var requireable in requireables)
Console.WriteLine( requireable.Id );
Now things get freaky. I get the results...
1
1
This makes no sense to me. It shouldn't work. I can even query the individual properties of each object, and they have retained their type. Even if I run the insertion, close the application, then run the retrieval (so as to avoid the possibility of caching), they still have the right types. But the following does not work.
class SomethingThatHasRequireables
{
// ...
public virtual IList<IRequirement> Requirements { get; set; }
}
Trying to add to that collection fails (as I expect it to). Here is why I am confused.
If I can add to the generic IList<IRequirement> in my session, why not in an object?
How is nHibernate understanding the difference between two entities with the same Id,
if they are both mapped as the same kind of object, in one scenario, and not the other?
Can someone explain to me what in the world is going on here?
The suggested approach is to use SubclassMap<T>, however the problem with that is the number of identities, and the size of the table. I am concerned about scalability and performance if multiple objects (up to about 8) are referencing identities from one table. Can someone give me some insight on this one specifically?
Take a look at the chapter Inheritance mapping in the reference documentation. In the chapter Limitations you can see what's possible with which mapping strategy.
You've chose one of the "table per concrete class" strategies, as far as I can see. You may need <one-to-many> with inverse=true or <many-to-any> to map it.
If you want to avoid this, you need to map IRequirement as a base class into a table, then it is possible to have foreign keys to that table. Doing so you turn it into a "table per class-hierarchy" or "table per subclass" mapping. This is of course not possible if another base class is already mapped. E.g. SomeKindOfObject.
Edit: some more information about <one-to-many> with inverse=true and <many-to-any>.
When you use <one-to-many>, the foreign key is actually in the requirement tables pointing back to the Item. This works well so far, NH unions all the requirement tables to find all the items in the list. Inverse is required because it forces you to have a reference from the requirement to the Item, which is used by NH to build the foreign key.
<many-to-any> is even more flexible. It stores the list in an additional link table. This table has three columns:
the foreign key to the Item,
the name of the actual requirement type (.NET type or entity name)
and the primary key of the requirement (which can't be a foreign key, because it could point to different tables).
When NH reads this table, it knows from the type information (and the corresponding requirement mapping) in which other tables the requirements are. This is how any-types work.
That it is actually a many-to-many relation shouldn't bother you, it only means that it stores the relation in an additional table which is technically able to link a requirement to more then one item.
Edit 2: freaky results:
You mapped 3 tables: IRequirement, ObjectThatImplementsRequirement, AnotherObjectThatHasRequirement. They are all completely independent. You are still on "table per concrete class with implicit polymorphism". You just added another table with containing IRequirements, which may also result in some ambiguity when NH tries to find the correct table.
Of course you get 1, 1 as result. The have independent tables and therefore independent ids which both start with 1.
The part that works: NHibernate is able to find all the objects implementing an interface in the whole database when you query for it. Try session.CreateQuery("from object") and you get the whole database.
The part that doesn't work: On the other side, you can't get an object just by id and interface or object. So session.Get<object>(1) doesn't work, because there are many objects with id 1. The same problem is with the list. And there are some more problems there, for instance the fact that with implicit polymorphism, there is no foreign key specified which points from every type implementing IRequirement to the Item.
The any types: This is where the any type mapping comes in. Any types are stored with additional type information in the database and that's done by the <many-to-any> mapping which stores the foreign key and type information in an additional table. With this additional type information NH is able to find the table where the record is stored in.
The freaky results: Consider that NH needs to find both ways, from the object to a single table and from the record to a single class. So be careful when mapping both the interface and the concrete classes independently. It could happen that NH uses one or the other table depending on which way you access the data. This may have been the cause or your freaky results.
The other solution: Using any of the other inheritance mapping strategies, you define a single table where NH can start reading and finding the type.
The Id Scope: If you are using Int32 as id, you can create 1 record each second for 68 years until you run out of ids. If this is not enough, just switch to long, you'll get ... probably more then the database is able to store in the next few thousand years...

Fluent NHibernate: How do you change the underlying sql type for an automapped collection of strings?

I have a class:
public class ParentClass
{
//other stuff
IList<string> ChildPages
}
When 'IList<string> ChildPages' gets automapped by Fluent NHibernate a 'ChildPages' join table is created with a nvarchar(255) backing field for each string in the collection.
But the problem is that I want the sql backing field to be 'text', so that I can have lengthy entries for this entity.
What's the easiest way to make this change?
How do you change the underlying type of automapped primitive collections?
Also, for extra points, how would you do this with a convention or mapping overrides?
Thx!
You can setup an override convention so that strings use text instead of nvarchar2 (255), as shown in the solution on this other thread. If you only want such behavior for a specific property, something like this in your fluent configuration would work:
AutoMap
.AssemblyOf<ParentClass>()
.Override<ChildPage>(map =>
{
mapping.Map(x => x.Page).CustomType("StringClob").CustomSqlType("text");
});