简体   繁体   中英

Fluent NHibernate Generated Audits

I need some help setting up my Fluent NHibernate POCO class structure. I'm trying to simply have a way to make an object auditable. On Create, I want my created and modified datetimes to be set and on update, I want my modified to be updated. I've been following some examples, but I have hit a road block. This is my current setup:

IAuditable.cs

namespace ZeroBase.Domain.Entities
{
public interface IAuditable
{
    DateTime Created
    {
        get;
    }

    DateTime Modified
    {
        get;
    }

    string CreatedPropertyName
    {
        get;
    }

    string ModifiedPropertyName
    {
        get;
    }

    void SetCreationDate(DateTime created);
    void SetModifiedDate(DateTime modified);
}
}

AuditableEntity.cs

namespace ZeroBase.Domain.Entities
{
public class AuditableEntity<T> : IAuditable
{
    public DateTime Created { get; private set; }
    public DateTime Modified { get; private set; }

    void IAuditable.SetCreationDate(DateTime created)
    {
        this.Created = created;
    }

    void IAuditable.SetModifiedDate(DateTime modified)
    {
        this.Modified = modified;
    }

    string IAuditable.CreatedPropertyName
    {
        get
        {
            string createdPropName = "Created";

        #if DEBUG
            CheckIfPropertyExists(createdPropName);
        #endif

            return createdPropName;
        }
    }

    string IAuditable.ModifiedPropertyName
    {
        get
        {
            string modifiedPropName = "Modified";

        #if DEBUG
            CheckIfPropertyExists(modifiedPropName);
        #endif

            return modifiedPropName;
        }
    }

    private void CheckIfPropertyExists(string propertyName)
    {
        PropertyInfo pi = this.GetType().GetProperty(propertyName);
        Debug.Assert(pi != null, String.Format("There exists no property {0}", propertyName));
    }
}
}

User.cs

namespace ZeroBase.Domain.Entities
{
public class User : AuditableEntity<User>
{
    public virtual Guid Id { get; set; }
    public virtual string Username { get; set; }
    public virtual string Password { get; set; }
    public virtual string FirstName { get; set; }
    public virtual string LastName { get; set; }
    public virtual string EmailAddress { get; set; }
    public virtual IEnumerable<Comment> Comments { get; set; }
}
}

AuditInterceptor.cs

namespace ZeroBase.Infrastructure.Data
{
public class AuditInterceptor : EmptyInterceptor
{
    public override bool OnFlushDirty(object entity, object id, object[] currentState, object[] previousState,
        string[] propertyNames, NHibernate.Type.IType[] types)
    {
        IAuditable auditableObject = entity as IAuditable;

        if (auditableObject != null)
        {
            for (int i = 0; i < propertyNames.Length; i++)
            {
                if (propertyNames[i] == auditableObject.ModifiedPropertyName)
                {
                    currentState[i] = DateTime.Now;
                }
            }
            return true;
        }

        return false;
    }

    public override bool OnSave(object entity, object id, object[] state, string[] propertyNames, NHibernate.Type.IType[] types)
    {
        IAuditable auditableObject = entity as IAuditable;

        if (auditableObject != null)
        {
            DateTime currentDate = DateTime.Now;

            for (int i = 0; i < propertyNames.Length; i++)
            {
                if (propertyNames[i] == auditableObject.CreatedPropertyName)
                {
                    state[i] = currentDate;
                }
                if (propertyNames[i] == auditableObject.ModifiedPropertyName)
                {
                    state[i] = currentDate;
                }
            }

            System.Diagnostics.Debug.WriteLine("interceptor: created: " + auditableObject.Created);
            System.Diagnostics.Debug.WriteLine("interceptor: modified: " + auditableObject.Modified);

            return true;
        }

        return false;
    }
}
}

AuditMap.cs

namespace ZeroBase.Infrastructure.Data
{
public class AuditMap<T>: ClassMap<T> where T : AuditableEntity<T>
{
    public AuditMap()
    {
        Map(p => p.Created);
        Map(p => p.Modified);
    }
}
}

UserMap.cs

namespace ZeroBase.Infrastructure.Data
{
public class UserMap : AuditMap<User>
{
    public UserMap()
    {
        Id(x => x.Id)
            .Column("Id")
            .GeneratedBy.Guid();
        Map(x => x.Username);
        Map(x => x.Password);
        Map(x => x.FirstName);
        Map(x => x.LastName);
        Map(x => x.EmailAddress);
        HasMany(x => x.Comments);
        Table("Users");
    }
}
}

SessionHelper.cs

_sessionFactory = Fluently.Configure()

            // Set up database connection
            .Database(MsSqlConfiguration.MsSql2005
                .ConnectionString(x => x.Is(_connectionString))
                //.ShowSql()
            )

            // Use class mappings
            .Mappings(m => m.FluentMappings
                .AddFromAssemblyOf<UserMap>())

            .ExposeConfiguration(c => c.SetInterceptor(new AuditInterceptor()))

            .BuildSessionFactory();

When I try to run this, I get this runtime error: The following types may not be used as proxies: ZeroBase.Domain.Entities.User: method get_Created should be 'public/protected virtual' or 'protected internal virtual' ZeroBase.Domain.Entities.User: method get_Modified should be 'public/protected virtual' or 'protected internal virtual'"}

What is this trying to tell me?

Does this have anything to do with Fluent NHibernate?

I'm a little confused and would love some help!

Created and Modified properties in your AuditableEntity<T> class need to be virtual. This is a requirement of NHibernate, if you are using lazy loading (on by default).

Also, there are some questions about it here on SO.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM