Temporarily turn off identity column with Fluent AutoMap?

642 Views Asked by At

I have begun to test Fluent NHibernate in C# I have a well normalized object structure with 20 related classes. I currently use Fluent 1.3 with NHibernate 3.2. So far I have managed to use the AutoMap feature which suits me fine, Very convenient!

BUT ... 3 of the tables are "enum tables" that need to have their records set with specific Id value. I tried to make manual mappings of these tables and let the rest be automapped. But when the manual table is created it fails because it references a table that is automapped (and not available for manual mapper?)

Is it possible to use AutoMapping but for some very few classes override identity creation on primary key? I tried to make a custom convention but without success.

public class OverrideIdentityGeneration : Attribute
{
}

public class ConventionIdentity : AttributePropertyConvention<OverrideIdentityGeneration>
{
    protected override void Apply(OverrideIdentityGeneration attribute, IPropertyInstance instance)
    {
        instance.Generated.Never();
    }
}

Is there some other way? It would be sad to be forced back to use manual mapping for all classes ....

2

There are 2 best solutions below

0
On BEST ANSWER

I used the idea given by Fifo and extended it to use a custom attribute instead. To make code readable and avoid redundance when using similar idea in other conventions I added an extension method to check for custom attribute.

This is the code I ended up with:

/// <summary>
/// Convention to instruct FluentNHIbernate to NOT generate identity columns
/// when custom attribute is set.
/// </summary>
public class ConventionIdentity : IIdConvention
{
    public void Apply(IIdentityInstance instance)
    {
        if(instance.CustomAttributeIsSet<NoIdentity>())
            instance.GeneratedBy.Assigned();
    }
}

/// <summary>
/// Custom attribute definition.
/// </summary>
public class NoIdentity : Attribute
{
}

/// <summary>
/// Example on how to set attribute.
/// </summary>
public class Category
{
    [NoIdentity]
    public int Id { get; set; }
    public string Name { get; set; }
}

public static class IInspectorExtender
{
    /// <summary>
    /// Extender to make convention usage easier.
    /// </summary> 
    public static T GetCustomAttribute<T>(this IInspector instance)
    {
        var memberInfos = instance.EntityType.GetMember(instance.StringIdentifierForModel);
        if(memberInfos.Length > 0)
        {
            var customAttributes = memberInfos[0].GetCustomAttributes(false);
            return customAttributes.OfType<T>().FirstOrDefault();
        }
        return default(T);
    }
}
3
On
class MyIdConvention : IIdConvention
{
    public void Apply(IIdentityInstance instance)
    {
        if (instance.EntityType == ...)
        {
            instance.GeneratedBy.Assigned();
        }
    }
}

Update:

for enum-like classes it's often easier to define an enum as id

class ConfigValue
{
    public virtual Config Id { get; set; }
}

// the convention is easy
if (instance.EntityType.IsEnum)
{
    instance.GeneratedBy.Assigned();
    // to save as int and not string
    instance.CustomType(typeof(Config));
}

// querying without magic int values
var configValue = Session.Get<ConfigValue>(Config.UIColor);