Search code examples
nhibernatenhibernate-envers

Auditing user using NHibernate Envers fluentconfiguration


I am trying to use NHibernate Envers to log an additional field "user". I have followed several code examples that seem to vary a bit when it comes to syntax, probably because some of them are a bit out of date. However I can't get it to work.

I'm getting this exception:
Only one property may have the attribute [RevisionNumber]!

My Custom Revision Entity:

public class CustomRevisionEntity
{
    public virtual int Id { get; set; }
    public virtual DateTime RevisionTimestamp { get; set; }
    public virtual Guid UserIdentityId { get; set; }

    public override bool Equals(object obj)
    {
        if (this == obj) return true;
        var revisionEntity = obj as CustomRevisionEntity;
        if (revisionEntity == null) return false;

        var that = revisionEntity;

        if (Id != that.Id) return false;
        return RevisionTimestamp == that.RevisionTimestamp;
    }

    public override int GetHashCode()
    {
        var result = Id;
        result = 31 * result + (int)(((ulong)RevisionTimestamp.Ticks) ^ (((ulong)RevisionTimestamp.Ticks) >> 32));
        return result;
    }
}

My IRevisionListener:

public class RevInfoListener : IRevisionListener
{
    public void NewRevision(object revisionEntity)
    {
        var casted = revisionEntity as CustomRevisionEntity;

        if (casted != null)
        {
            casted.UserIdentityId = Guid.NewGuid(); // TODO
        }
    }         
}

First I use mapping by code to map the entity:

_modelMapper.Class<CustomRevisionEntity>(entity =>
{
    entity.Property(x => x.Id);
    entity.Property(x => x.RevisionTimestamp);
    entity.Property(x => x.UserIdentityId);
});

Then I configure Envers and NHibernate

var enversConf = new FluentConfiguration();
enversConf.SetRevisionEntity<CustomRevisionEntity>(x => x.Id, x => x.RevisionTimestamp, new RevInfoListener());
enversConf.Audit<OrganizationEntity>().Exclude(x => x.Version);
configuration.IntegrateWithEnvers(enversConf); // This is the nh-configuration

The last line gives me the exception:
Only one property may have the attribute [RevisionNumber]!

Anyone have any ideas? Myself I would speculate that the default revision entity is still used somehow and when I try to register my custom revision entity this happens.


Solution

  • The error message occurred because the Id property was being mapped twice.

    In our mapping class we had this

    _modelMapper.BeforeMapClass += (modelInspector, type, classCustomizer) => classCustomizer.Id(type.GetProperty("Id"), (idMapper) =>                                                                                                                                     
    {
        idMapper.Access(Accessor.Property);
        idMapper.Generator(Generators.GuidComb);
    });
    

    Then we tried mapping Id again as a property of the CustomRevisionEntity

    The final mapping:

    _modelMapper.Class<CustomRevisionEntity>(entity =>
    {
        entity.Id<int>(x => x.Id, mapper => mapper.Generator(Generators.Identity));
        entity.Property(x => x.RevisionDate);
        entity.Property(x => x.UserIdentityId);
    });