How can I make a where clause on a reference in fluent-nhibernate mapping - nhibernate

There exists such a method on HasMany and HasManyToMany but for some reason there isn't such a mechanism on References.
We have an object that references an other object that can be updated and saved as new versions but from our child object we doesn't really care we only want to load the latest version of the related object. The mapping cannot use the primary key for the related object since this will change for each version of the object so instead we want to map the related object to an property that doesn't change between versions and then make a where-clause to only selected the matching element with the highest version.
So our mapping is like the following
References(p => p.RelatedObjectIdentifier).PropertyRef("MatchingPropIdentifier").Not.Nullable;
We would like to do something like this
References(p => p.RelatedObjectIdentifier).PropertyRef("MatchingPropIdentifier").Where(p => p.IsLatest).Not.Nullable;
Of course we would update the property IsLatest (bool property) for each saving of the related object.
So since the Where(p => p.IsLatest) doesn't exist on a References for a classmap/subclassmap how can we make this happen in any other way?

You can only use the Where() restriction, which:
Defines a SQL 'where' clause used when retrieving objects of this type.
on the class map of the referenced type.
Example:
public class RelatedObjectMap : ClassMap<RelatedObject>
{
public RelatedObjectMap()
{
Table("RelatedObjectTable");
//Id() etc.
Where("MatchingPropIdentifier IS NOT NULL)");
}
}

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.

Nhibernate - Mapping information

I'm using Fluent NHibernate in a simple project and I would be able to get some informations about identifier property name, foreign key property name and version property name.
Nowdays, I know just one way to retrieve the identifier property name:
string primaryKeyName = NHibernateHelper.OpenSession().SessionFactory.GetClassMetadata(typeof(MyClass).Name).IdentifierPropertyName;
Is There some way to get foreign and version proprety name too?
Don't really know what you mean but the meta data object has all the information about the mapping of your object
Internal version if you meant this?
var postMeta = sessionFactory.GetClassMetadata(typeof(Post));
var version = postMeta.VersionProperty;
Then there are some collections which store the types, nullability, names and laziness of all the properties of your entity
var lazzyProperties = meta.PropertyLaziness;
var propertyNames = meta.PropertyNames;
//etc...
the PropertyTypes array actually stores a Bag object if there is a Bag mapping etc... Somewhere in those objects you'll find some properties where nHibernate internally stores the foreign key relationships, from<->to etc...
Hope this helps

NHibernate SaveOrUpdate() improperly working with GeneratedBy.Assigned()

NHibernate's documentations specifically says
5.1.4.7. Assigned Identifiers
If you want the application to assign identifiers (as opposed to having NHibernate generate them), you may use the assigned generator. This special generator will use the identifier value already assigned to the object's identifier property. Be very careful when using this feature to assign keys with business meaning (almost always a terrible design decision).
Due to its inherent nature, entities that use this generator cannot be saved via the ISession's SaveOrUpdate() method. Instead you have to explicitly specify to NHibernate if the object should be saved or updated by calling either the Save() or Update() method of the ISession.
But I am using assigned identifiers and session.SaveOrUpdate() and I'm not getting an error/warning of any sort.
What am I missing? Did they change how SaveOrUpdate behaves and now it can be used with assigned identifiers?
I am also using Fluent NHibernate's auto mapping.
Here's the code:
public class MyIDConvention : IIdConvention
{
public void Apply(IIdentityInstance instance)
{
instance.GeneratedBy.Assigned();
}
}
private static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure().Database(SQLiteConfiguration.Standard.UsingFile("testDB.db"))
.Mappings(m => m.AutoMappings.Add(AutoMap.AssemblyOf<Product>(cfg).Conventions.Add<MyIDConvention>()
.BuildSessionFactory();
}
I'm expecting an error when I do:
Product myProduct = new Product(presetID);
session.SaveOrUpdate(myProduct);
transaction.Commit();
but nothing happens.
If I had left out the myIDConvention, then I get the error:
NHibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect).
Can anyone explain to me what is going on?
When using assigned ids NHibernate can determine if the entity is persistent by comparing the id to the unsaved value setting. My understanding is that the unsaved value setting allows SaveOrUpdate to be used and the documentation you referenced is outdated/misleading.
For example, if your id is int the default unsaved-value is 0.
5.1.4
unsaved-value (optional - defaults to a "sensible" value): An
identifier property value that indicates that an instance is newly
instantiated (unsaved), distinguishing it from transient instances
that were saved or loaded in a previous session.

Castle ActiveRecord Error With View: NHibernate.PropertyNotFoundException for generated key

I'm mapping a view using ActiveRecord, which means I need a primary key. I don't have one, so I'm using ROW_NUMBER() to create one in the view definition to placate the system. However, I don't seem to know how to map it properly. I'm getting:
Could not find field 'stupidID' in class 'blah_blah'
NHibernate.PropertyNotFoundException: Could not find field 'stupidID' in class 'blah_blah'
My mapping looks like this. There is no
public long? stupidID;
[PrimaryKey("StupidId", Access = PropertyAccess.NosetterLowercaseUnderscore)]
public long? StupidId
{
get { return stupidID; }
}
Can anyone see what I'm missing?
NosetterLowercaseUnderscore means that by convention a prefix '_' is used and it's lowercase, so the field should be called _stupidid instead of stupidID.
Also, the PK shouldn't be a nullable type. I'd use long instead of long?

Enum to integer mapping causing updates on every flush

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.)