IIdConvention "overrides" IAutoMapping - fluent-nhibernate

I'm using a specific convention for my Id tables and I'd like to override the way the ID of a specific entity is mapped. In this scenario, most of the entities should a key on the form Class+ID (ex.: EmployeeId, DepartmentId, etc), but I'd like to use a specific property for a couple of enties. So, I've added a default convention rule:
class MyPrimaryKeyConvention:IIdConvention{
public void Apply(IIdentityInstance instance) {
instance.Column(instance.EntityType.Name + "Id");
instance.GeneratedBy.Assigned();
}
}
And then, I thought I could override the mappings of the "special" EmployeeShortInfo class by doing something like this:
public class EmployeeShortInfoIdOverride: IAutoMappingOverride<Dtos.EmployeeShortInfo> {
public void Override(AutoMapping<Dtos.EmployeeShortInfo> mapping) {
mapping.Id(e => e.EmployeeId);
}
}
Unfortunately, fluent will try to use EmployeeShortInfoId instead of using the EmployeeId property. Shouldn't IAutoMappingOverride override the default convention of a class?
thanks.

Related

Can the column names of an ICompositeUserType be controlled in a FluentNHibernate convention?

I've created an IUserTypeConvention convention to use an ICompositeUserType implementation on all properties of a matching type:
public abstract class CompositeUserTypeConvention<TUserType>
: IUserTypeConvention
where TUserType : ICompositeUserType, new()
{
public virtual void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
{
var userType = new TUserType();
criteria.Expect(x => x.Type == userType.ReturnedClass);
}
public virtual void Apply(IPropertyInstance instance)
{
instance.CustomType<TUserType>();
}
}
When applying this, FluentNHibernate generates column names for each property of the composite type using a convention of {memberpropertyname}_{compositepropertyname}.
In the case of a composite type like Money with properties Amount and Currency, if I were to have a property on my entity called Price of type Money, the columns expected are called Price_Currency and Price_Amount.
What I would like is to change this convention to remove the underscore, but I don't know how or if this is possible.
The CustomType<T>() method has an overload which accepts columnPrefix as an argument. The default behaviour is to pass the property name + "_" as this value. Specifying the value explicitly gave the desired result:
public virtual void Apply(IPropertyInstance instance)
{
instance.CustomType<TUserType>(instance.Name);
}

Fluent NHibernate set all IDs to assigned

I know I can manually set each Id property to assigned using Assigned().
Is there any way of applying this globally, as I want to do it on every entity?
Sure, just register FluentNHibernate convention like this:
public class AssignedIdConvention : IIdConvention
{
public void Apply(IIdentityInstance instance)
{
instance.GeneratedBy.Assigned();
}
}
Registration goes like this:
Fluently.Configure()
.Mappings(...)
.Conventions.Add<AssignedIdConvention>()

Fluent nhibernate automapping collection

I am trying to map my collections with FNHib automapping. The problems that I want to solve are:
1) I want all my collections in the project to be mapped via private field. How can I say that globally?
2) Is there any way to automap bidirectional relationship without explicitly overriding each of my entities.
class OrganizationEntity example:
private ISet<> _collectionWarehouse;
public virtual IEnumerable<WarehouseEntity> CollectionWarehouse
{
get{return _collectionWarehouse; }
set{_collectionWarehouse = new HashedSet<WarehouseEntity>((ICollection<WarehouseEntity>)value)}
}
Class WarehouseEntity example:
public virtual OrganizationEntity Organization{get;set;}
You can map your collections to a private field 'globally' with the following convention:
// assumes camel case underscore field (i.e., _mySet)
public class CollectionAccessConvention : ICollectionConvention
{
public void Apply(ICollectionInstance instance) {
instance.Access.CamelCaseField(CamelCasePrefix.Underscore);
}
}
Whenever you want to set a 'global' automap preference in FNH, think conventions. The you use the IAutoOverride on a given class map if you need to.
As far has the set (a HashSet is usually what I really want also) part, the last time I had to do some mapping, I did need to do an override, like:
public class ActivityBaseMap : IAutoMappingOverride<ActivityBase>
{
public void Override(AutoMapping<ActivityBase> m)
{
...
m.HasMany(x => x.Allocations).AsSet().Inverse();
}
}
I do agree that should translate into a convention though, and maybe you can do that these days. Please post if you figure it out.
HTH,
Berryl
CODE TO USE A HASHSET as an ICollection =================
public virtual ICollection<WarehouseEntity> Wharehouses
{
get { return _warehouses ?? (_warehouses = new HashSet<WarehouseEntity>()); }
set { _warehouses = value; }
}
private ICollection<WarehouseEntity> _warehouses;

How to map an interface in nhibernate?

I'm using two class NiceCustomer & RoughCustomer which implment the interface ICustomer.
The ICustomer has four properties. They are:
Property Id() As Integer
Property Name() As String
Property IsNiceCustomer() As Boolean
ReadOnly Property AddressFullText() As String
I don't know how to map the interface ICustomer, to the database.
I get an error like this in the inner exception.
An association refers to an unmapped class: ICustomer
I'm using Fluent and NHibernate.
You can map directly to interfaces in NHibernate, by plugging in an EmptyInterceptor during the configuration stage. The job of this interceptor would be to provide implementations to the interfaces you are defining in your mapping files.
public class ProxyInterceptor : EmptyInterceptor
{
public ProxyInterceptor(ITypeHandler typeHandler) {
// TypeHandler is a custom class that defines all Interface/Poco relationships
// Should be written to match your system
}
// Swaps Interfaces for Implementations
public override object Instantiate(string clazz, EntityMode entityMode, object id)
{
var handler = TypeHandler.GetByInterface(clazz);
if (handler == null || !handler.Interface.IsInterface) return base.Instantiate(clazz, entityMode, id);
var poco = handler.Poco;
if (poco == null) return base.Instantiate(clazz, entityMode, id);
// Return Poco for Interface
var instance = FormatterServices.GetUninitializedObject(poco);
SessionFactory.GetClassMetadata(clazz).SetIdentifier(instance, id, entityMode);
return instance;
}
}
After this, all relationships and mappings can be defined as interfaces.
public Parent : IParent {
public int ID { get; set; }
public string Name { get; set; }
public IChild Child { get; set; }
}
public Child : IChild {
public int ID { get; set; }
public string Name { get; set; }
}
public class ParentMap : ClassMap<IParent>
{
public ParentMap()
{
Id(x => x.ID).GeneratedBy.Identity().UnsavedValue(0);
Map(x => x.Name)
}
}
...
This type of technique is great if you want to achieve true decoupling of your ORM, placing all configuration/mappings in a seperate project and only referencing interfaces. Your domain layer is then not being polluted with ORM, and you can then replace it at a later stage if you need to.
how are you querying? If you're using HQL you need to import the interface's namespace with an HBM file with this line:
<import class="name.space.ICustomer, Customers" />
If you're using Criteria you should just be able to query for ICustomer and it'll return both customer types.
If you're mapping a class that has a customer on it either through a HasMany, HasManyToMany or References then you need to use the generic form:
References<NiceCustomer>(f=>f.Customer)
If you want it to cope with either, you'll need to make them subclasses
Subclassmap<NiceCustomer>
In which case I think you'll need the base class Customer and use that for the generic type parameter in the outer class:
References<Customer>(f=>f.Customer)
Regardless, you shouldn't change your domain model to cope with this, it should still have an ICustomer on the outer class.
I'm not sure if the 1.0RTM has the Generic form working for References but a quick scan of the changes should show the change, which I think is a two line addition.
It is not possible to map an interface in nhibernate. If your goal is to be able to query using a common type to retrieve both types of customers you can use a polymorphic query. Simply have both your classes implement the interface and map the classes normally. See this reference:
https://www.hibernate.org/hib_docs/nhibernate/html/queryhql.html (section 11.6)

Using Fluent NHibernate Auto Mapping to map IDs of type object from base Entity class

In the project I'm working on now, we have base Entity class that looks like this:
public abstract class Entity<T> where T : Entity<T>
{
public virtual object Id { get; protected set }
// Equals, GetHashCode overrides, etc...
}
Most classes inheriting from Entity should map Id to int column in SQL Server database, but at least one will need to map to long (bigint).
Is it possible to create FluentNH Auto Mapping convention to map those object Ids to int by default? Then we could use another convention or IAutoMappingOverride to handle long Ids.
Thanks!
To answer my own question... It's possible.
You can define convention like this:
internal class PrimaryKeyConvention : IIdConvention
{
public bool Accept(IIdentityPart id)
{
return true;
}
public void Apply(IIdentityPart id)
{
if (<ID should be long>)
id.SetAttribute("type", "Int64");
else
id.SetAttribute("type", "Int32");
}
}