Nhibernate QueryOver by Enum Flags - nhibernate

I have a query by QueryOver :
public IList<Person> SearchTest(PersonEnumType type)
{
var q = SessionInstance.QueryOver<Person>();
q = q.Where(x => (x.PersonEnumType & type) == type);
return q.List<Person>();
}
and PersonEnumType is a Enum flags :
[Flags]
public enum PersonEnumType
{
Employee1 = 1,
Employee2 = 2,
Employee3 = 4
}
This throws Could not determine member from (Convert(x.PersonEnumType) & Convert(value(NHibernate.Repository.PersonRepositoryNh+<>c__DisplayClass2).type))
Of course this works in Nhibernate.Linq.
Why?

if you've mapped your property properly in your mapping file:
<property name="PersonEnumType" type="MyApp.PersonEnumType, MyApp">
<column name="Person" default="1" />
</property>
You can achieve what you're looking for using filters.
I don't know if this is the only solution but, here it goes:
You can create a filter definition:
<filter-def name="PersonEnumTypeFilter">
<filter-param name="personType" type="MyApp.PersonEnumType, MyApp"/>
</filter-def>
and implement it in your class mapping:
<filter name="PersonEnumTypeFilter" condition="(:personType & PersonEnumType) = PersonEnumType"/>
Now you can switch on your filter:
public IList<Person> SearchTest(PersonEnumType type)
{
SessionInstance.EnableFilter("PersonEnumTypeFilter").SetParameter("personType", type);
var q = SessionInstance.Query<Person>();
return q.ToList<Person>();
}
You can read more about filters here.

Related

Nhibernate many-to-many with extra column,

I am little bit new to NHibernate. I wish to implement a web application using asp.net using C#.
I have following database schemas:
Database Schemas
Here is my NHibernate Mapping file. I am not sure whether my mapping is correct or not. Please correct me if I made it wrong.
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="TelDir.Core.Domain.Status, TelDir.Core" table="tblStatus" lazy="false">
<id name="ID" column="StatusID" unsaved-value="0">
<generator class="identity" />
</id>
<property name="StatusCode" column="StatusCode" />
<property name="StatusName" column="StatusName" />
<!--
<set name="WorkOrderStatus" table="tblWorkOrderStatus" inverse="true">
<key column="StatusID" />
<one-to-many class="TelDir.Core.Domain.WorkOrderStatus, TelDir.Core" />
</set>
-->
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="TelDir.Core.Domain.WorkOrder, TelDir.Core" table="tblWorkOrder" lazy="false">
<id name="ID" column="WOID" unsaved-value="0">
<generator class="identity" />
</id>
<property name="WorkOrderRef" column="WORef" />
<property name="WorkOrderDesc" column="WODesc" />
<set name="WorkOrderStatus" table="tblWorkOrderStatus" inverse="true">
<key column="WOID" />
<one-to-many class="TelDir.Core.Domain.WorkOrderStatus, TelDir.Core" />
</set>
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="TelDir.Core.Domain.WorkOrderStatus, TelDir.Core" table="tblWorkOrderStatus" lazy="false">
<composite-id>
<key-many-to-one name="WorkOrder" column="WOID"/>
<key-many-to-one name="Status" column="StatusID"/>
</composite-id>
<property name="LastModifyDateTime" column="LastModifiedOn" type="Timestamp" />
<property name="CreatedBy" column="CreatedBy" />
</class>
</hibernate-mapping>
And my POCO class are presented as below
public class Status : DomainObject<Int16>
{
private string _statuscode = "";
private string _statusname = "";
//private ISet<WorkOrderStatus> _workorder_status = new HashedSet<WorkOrderStatus>() ;
public Status() { }
public Status(string statusCode, string statusName) {
this._statuscode = statusCode;
this._statusname = statusName;
}
public string StatusCode {
get { return _statuscode ; }
set { _statuscode = value; }
}
public string StatusName
{
get { return _statusname; }
set { _statusname = value; }
}
/*
public ISet<WorkOrderStatus> WorkOrderStatus
{
get { return (_workorder_status); }
protected set { _workorder_status = value; }
}
*/
}
public class WorkOrder : DomainObject<long>
{
private string _workorder_ref = "";
private string _workorder_desc = "";
private ISet<WorkOrderStatus> _workorder_status = new HashedSet<WorkOrderStatus>();
public WorkOrder() { }
public WorkOrder(string wref, string wdecs) {
this._workorder_ref = wref;
this._workorder_desc = wdecs;
}
public string WorkOrderRef {
get { return _workorder_ref ; }
set { _workorder_ref = value; }
}
public string WorkOrderDesc
{
get { return _workorder_desc; }
set { _workorder_desc = value; }
}
public ISet<WorkOrderStatus> WorkOrderStatus
{
get { return (_workorder_status); }
protected set { _workorder_status = value; }
}
public void AddStatus(Status st, DateTime dt)
{
WorkOrderStatus obj = new WorkOrderStatus();
obj.WorkOrder = this;
obj.Status = st;
obj.LastModifyDateTime = dt;
_workorder_status.Add(obj);
}
}
public class WorkOrderStatus
{
private DateTime _lastmodifydt;
private WorkOrder _workorder;
private Status _status;
private int _createdby;
public WorkOrderStatus() {
}
public DateTime LastModifyDateTime{
get { return _lastmodifydt; }
set { _lastmodifydt = value; }
}
public WorkOrder WorkOrder
{
get { return _workorder; }
set { _workorder = value; }
}
public Status Status
{
get { return _status; }
set { _status = value; }
}
public int CreatedBy {
get { return _createdby; }
set { _createdby = value; }
}
public override bool Equals(object other)
{
//if (this == other) return true;
//WorkOrderStatus obj = other as WorkOrderStatus;
//if (obj == null) return false; // null or not a cat
//if (_lastmodifydt != obj._lastmodifydt ) return false;
//return true;
if (other == null)
return false;
WorkOrderStatus t = other as WorkOrderStatus;
if (t == null)
return false;
if (WorkOrder == t.WorkOrder && Status == t.Status && _lastmodifydt == t.LastModifyDateTime )
return true;
return false;
}
public override int GetHashCode()
{
unchecked
{
int result;
result = _lastmodifydt.GetHashCode();
result = 29 * result + WorkOrder.GetHashCode() + Status.GetHashCode();
return result;
}
//return (WorkOrder.ID + "|" + Status.ID + "|" + Status.StatusName).GetHashCode();
}
}
I want my data present in tables like this:
[tblWorkOrderStatus]
StatusID WOID LastModifiedOn CreatedBy
--------------------------------------------------------------------------
2 1 06/20/2012 09:45:40.209 1
[tblWorkOrder]
WOID WORef WODesc
-------------------------------------------
1 001 Test-001
[tblStatus]
StatusID StatusCode StatusName
-----------------------------------------------
1 'X001' OPEN
2 'X002' CLOSE
What should I do to add record to [tblWorkOrderStatus]?
I have written test code as following but I found no record add in association table [tblWorkOrderStatus], I dont know why it does not added.
WorkOrder Wo = new WorkOrder('001', 'Test-001');
daoFactory.GetWorkOrderDao().Save(Wo);
Status St = daoFactory.GetStatusDao().GetById(1, false);
//// Secode Methode
WorkOrderStatus _objWS = new WorkOrderStatus();
_objWS.WorkOrder = Wo;
_objWS.Status = St;
_objWS.LastModifyDateTime = DateTime.Now;
_objWS.CreatedBy = 1; //suppose 1 is current login UserID
Wo.WorkOrderStatus.Add(_objWS);
daoFactory.GetWorkOrderDao().Save(Wo);
I might missing something in POCO, NHibernate mapping file, or somewhere else. Could you please guide me to the right solution?
Best regards,
Here is my stacktrace :
" at System.ThrowHelper.ThrowKeyNotFoundException()\r\n
at System.Collections.Generic.Dictionary`2.get_Item(TKey key)\r\n
at NHibernate.Engine.StatefulPersistenceContext.RemoveEntity(EntityKey key)\r\n
at NHibernate.Action.EntityDeleteAction.Execute()\r\n
at NHibernate.Engine.ActionQueue.Execute(IExecutable executable)\r\n
at NHibernate.Engine.ActionQueue.ExecuteActions(IList list)\r\n
at NHibernate.Engine.ActionQueue.ExecuteActions()\r\n
at NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions(IEventSource session)\r\n
at NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent event)\r\n
at NHibernate.Impl.SessionImpl.Flush()\r\n
at NHibernate.Transaction.AdoTransaction.Commit()\r\n
at TelDir.Data.NHibernateSessionManager.CommitTransaction()
in E:\\OLD PC\\D\\WORKS\\PROJECT\\TelDIR\\Data\\NHibernateSessionManager.cs:line 120\r\n
at TelDir.Web.NHibernateSessionModule.CommitAndCloseSession(Object sender, EventArgs e)
in e:\\OLD PC\\D\\WORKS\\PROJECT\\TelDIR\\Web\\App_Code\\NHibernateSessionModule.cs:line 38\r\n
at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()\r\n
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)"
The main issue is that there is no cascade on WorkOrder.WorkOrderStatus, so NHibernate will not know to persist changes it finds in that collection when you save.
I changed WorkOrder.hbm.xml so the set looks like this:
<set name="WorkOrderStatus" table="tblWorkOrderStatus" inverse="true" cascade="all-delete-orphan">
<key column="StatusID" />
<one-to-many class="TelDir.Core.Domain.WorkOrderStatus, TelDir.Core" />
</set>
And then this test passed:
// Arrange
var workorder = new WorkOrder("001", "Test-001");
var status = new Status("1", "Status-1");
workorder.AddStatus(status, DateTime.Now);
WorkOrderStatus expected;
// Act
using (ISession session = _factory.OpenSession())
using (ITransaction tx = session.BeginTransaction())
{
session.Save(status);
session.SaveOrUpdate(workorder);
tx.Commit();
}
using (ISession session = _factory.OpenSession())
using (ITransaction tx = session.BeginTransaction())
{
expected = session.Query<WorkOrderStatus>()
.Fetch(s => s.Status)
.Fetch(s => s.WorkOrder)
.FirstOrDefault();
}
// Assert
expected.Should().NotBeNull();
expected.Status.Should().Be(status);
expected.WorkOrder.Should().Be(workorder);
Removing
Uncomment the ISet<WorkOrderStatus> WorkOrderStatus property on Status. Also, uncomment <set name="WorkOrderStatus" ... in Status.hbm.xml, and add the attribute cascade="all-delete-orphan" like you did on WorkOrder.
Add to WorkOrder:
public void RemoveStatus(WorkOrderStatus item)
{
if (!WorkOrderStatus.Contains(item)) return;
item.Status.WorkOrderStatus.Remove(item);
WorkOrderStatus.Remove(item);
}
Now, this test should pass:
// Arrange
var workorder = new WorkOrder("001", "Test-001");
var status = new Status("1", "Status-1");
workorder.AddStatus(status, DateTime.Now);
WorkOrderStatus expected;
// Act
using (ISession session = _factory.OpenSession())
using (ITransaction tx = session.BeginTransaction())
{
session.Save(status);
session.SaveOrUpdate(workorder);
tx.Commit();
}
using (ISession session = _factory.OpenSession())
using (ITransaction tx = session.BeginTransaction())
{
expected = session.Query<WorkOrderStatus>()
.Fetch(s => s.Status)
.Fetch(s => s.WorkOrder)
.FirstOrDefault();
expected.WorkOrder.RemoveStatus(expected);
tx.Commit();
}
using (ISession session = _factory.OpenSession())
using (ITransaction tx = session.BeginTransaction())
{
expected = session.Query<WorkOrderStatus>()
.Fetch(s => s.Status)
.Fetch(s => s.WorkOrder)
.FirstOrDefault();
}
// Assert
expected.Should().BeNull();

nhibernate queryover join with subquery to get aggregate column

I have been searching for several hours now how to do this, but can't seem to find anything to help me.
Here is the database model:
This is the SQL query I am trying to run:
SELECT b.*, a.Assignments FROM Branch b LEFT JOIN (
SELECT b.BranchID , COUNT(ab.BranchID) AS Assignments
FROM Branch b LEFT JOIN AssignmentBranch ab ON b.BranchID = ab.BranchID
GROUP BY b.BranchID
) a ON b.BranchID = a.BranchID
So, basically, I want to return a list of branches and a new column that represents the number of assignments for that branch.
Branch model
public class Branch : IEntity<int>
{
public virtual int ID
{
get;
set;
}
public virtual string Name { get; set; }
public virtual IList<AssignmentBranch> Assignments { get; set; }
}
AssignmentBranch model
public class AssignmentBranch : IEntity<int>
{
public virtual int ID
{
get;
set;
}
public virtual DateTime AssignedOn { get; set; }
public virtual Branch Branch { get; set; }
}
Here is my NHibernate configuration:
<class name="Branch" table="Branch">
<id name="ID" column="BranchID">
<generator class="identity"></generator>
</id>
<property name="Name"/>
<bag name="Assignments" cascade="none" inverse="true">
<key column="BranchID"/>
<one-to-many class="AssignmentBranch"/>
</bag>
<class name="AssignmentBranch" table="AssignmentBranch">
<id name="ID" column="AssignmentBranchID">
<generator class="identity"></generator>
</id>
<property name="AssignedOn" />
<property name="FromDate" />
<property name="ToDate" />
<many-to-one name="Assignment" column="AssignmentID" />
<many-to-one name="Branch" column="BranchID" />
I have tried this a number of ways, but I can't seem to find a way to join with a sub-query using QueryOver.
I tried like this:
// aliases
Branch branch = null; AssignmentBranch assignment = null;
var subquery = QueryOver.Of<Branch>(() => branch)
.Where(() => branch.Project.ID == projectID)
.JoinQueryOver<AssignmentBranch>(() => branch.Assignments, ()=> assignment,
NHibernate.SqlCommand.JoinType.LeftOuterJoin)
.SelectList(list => list
.SelectGroup(x=>x.ID)
.SelectCount(()=>assignment.ID)
);
var query = session.QueryOver<Branch>(()=>branch)
.JoinAlias(???) // how can I join with a sub-query?
.TransformUsing(Transformers.AliasToBean<BranchAssignments>())
.List<BranchAssignments>();
Can anyone help me please? It doesn't have to be with a sub-join exactly, maybe there is another better solution out there that I am missing...
Thank you,
Cosmin
After reading hundreds of similar questions in here, I have found the answer: a correlated sub-query. Like this:
// aliases
Branch branch = null; AssignmentBranch assignment = null;
var subquery = QueryOver.Of<AssignmentBranch>(() => assignment)
.Where(() => assignment.Branch.ID == branch.ID)
.ToRowCountQuery();
var query = session.QueryOver<Branch>(() => branch)
.Where(() => branch.Project.ID == projectID)
.SelectList
(
list => list
.Select(b => b.ID)
.Select(b => b.Name)
.SelectSubQuery(subquery)
)
.TransformUsing(Transformers.AliasToBean<BranchAssignments>())
.List<BranchAssignments>();
The similar question I got my answer from is this one.
its not that easy with QueryOver, because it is currently not possible to have statements in the FROM clause. One thing that comes to my mind (not the most efficient way i think)
var branches = session.QueryOver<Branch>().Future();
var assignmentMap = session.QueryOver<BranchAssignment>()
.Select(
Projections.Group<BranchAssignment>(ab => ab.Branch.Id).As("UserId"),
Projections.RowCount())
.Future<object[]>()
.ToDictionary(o => (int)o[0], o => (int)o[1]);
return branches.Select(b => new { Branch = branch, AssignmentCount = assignmentMap[branch.Id] });
with LINQ it would be
var branchesWithAssignementCount = session.Query<Branch>()
.Select(b => new { Branch = b, AssignmentCount = b.Branch.Count })
.ToList();

Cant query sybase with Nhibernate

Have started to use NHibernate on sybase ASE data, problem am facing is when I load entity I get below error
"System.IndexOutOfRangeException : Invalid index 0 for this OdbcParameterCollection with Count=0."
This is how I configure session
properties["connection.provider"] = "NHibernate.Connection.DriverConnectionProvider";
properties["connection.driver_class"] = "NHibernate.Driver.OdbcDriver";
properties["connection.connection_string"] = #"Driver={Adaptive Server Enterprise};server=;port=; db=;uid=;pwd=";
properties["dialect"] = "NHibernate.Dialect.SybaseASE15Dialect";
And object mapping
<class name="MenuGroup" table="MENU_GROUP">
<id name="Id" column="id" type="Int32">
<generator class="identity" />
</id>
<property name="Name" column="name" type="String" length="100" not-null="true" />
<property name="Position" column="position" type="Int32" />
</class>
and If I do
var menuGroup = _session.Get<Menu.MenuGroup>(1);
I get error
NHibernate.Exceptions.GenericADOException : could not load an entity: [DomainModel.Menu.MenuGroup#1][SQL: SELECT menugroup0_.id as id1_0_, menugroup0_.name as name1_0_, menugroup0_.position as position1_0_ FROM MENU_GROUP menugroup0_ WHERE menugroup0_.id=?]
----> System.IndexOutOfRangeException : Invalid index 0 for this OdbcParameterCollection with Count=0.
I solved this problem by creating my own connection driver
using NHibernate.Driver;
namespace Framework.Persistency
{
public sealed class MySybaseSQLAnywhereDriver : SybaseSQLAnywhereDriver
{
public override bool UseNamedPrefixInSql
{
//default is false
get { return true; }
}
public override bool UseNamedPrefixInParameter
{
//default is false
get { return true; }
}
public override string NamedPrefix
{
//default is string.Empty
get { return ":"; }
}
}
}
And use it in the NHibernate config:
configDictionary.Add(Environment.ConnectionDriver, typeof(MySybaseSQLAnywhereDriver).AssemblyQualifiedName);
moving away from odbc helped, changed the config to
properties["connection.provider"] = "NHibernate.Connection.DriverConnectionProvider";
properties["connection.driver_class"] = "NHibernate.Driver.SybaseAseClientDriver";
properties["connection.connection_string"] = #"server=*;port=5000; db=;user id=*;password=;";
properties["dialect"] = "NHibernate.Dialect.SybaseASE15Dialect";

NHibernate, joined subclass hierarchy, PreUpdate event data changes on an entity which is only modified in the PreUpdate event is not persisted

Overview: With NHibernate I am experimenting with a 3 layered hierarchy using joined subclasses. There is a Category, which inherits from AuditableEntity (to add PreUpdate and PreInsert audit trail), which finally inherits from an Entity.
Problem: None of the data changes to the AuditableEntity object, which are carried out exactly as Ayende’s blog post, are being persisted to the database. The AuditableEntity objects properties are successfully updated by the PreUpdate code, but it is as if NHibernate is not seeing the AuditableEntity as dirty as no update sql statement occurs.
Hbm:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Learning"
namespace="Learning.entities">
<class name="Entity" >
<id name="Id" type="guid">
<generator class="guid.comb"></generator>
</id>
<version name="Version"/>
<joined-subclass name="AuditableEntity" >
<key column="AuditableEntity_id"></key>
<property name="CreatedOn" ></property>
<property name="CreatedBy" ></property>
<property name="LastModifiedOn" ></property>
<property name="LastModifiedBy" ></property>
<joined-subclass name="Category">
<key column="AuditableEntity_id"></key>
<property name="Name" />
</joined-subclass>
</joined-subclass>
</class>
</hibernate-mapping>
NHibernate config for listeners:
<event type="pre-insert">
<listener class="Learning.eventlisteners.AuditInsertEventListener, Learning" />
</event>
<event type="pre-update">
<listener class="Learning.eventlisteners.AuditUpdateEventListener, Learning" />
</event>
PreUpdate code:
namespace Learning.eventlisteners
{
public class AuditInsertEventListener : IPreInsertEventListener
{
public bool OnPreInsert(PreInsertEvent #event)
{
var audit = #event.Entity as IAuditable;
if (audit == null)
return false;
var createdOn = DateTime.Now;
var createdBy = loggedOnProfile;
AuditCommon.Set(#event.Persister, #event.State, "CreatedOn", createdOn);
AuditCommon.Set(#event.Persister, #event.State, "CreatedBy", createdBy);
AuditCommon.Set(#event.Persister, #event.State, "LastModifiedOn", createdOn);
AuditCommon.Set(#event.Persister, #event.State, "LastModifiedBy", createdBy);
audit.CreatedOn = createdOn;
audit.CreatedBy = createdBy;
audit.LastModifiedOn = createdOn;
audit.LastModifiedBy = createdBy;
return false;
}
}
public static class AuditCommon
{
internal static void Set(IEntityPersister persister, IList<object> state, string propertyName, object value)
{
var index = Array.IndexOf(persister.PropertyNames, propertyName);
if (index == -1)
return;
state[index] = value;
}
}
public class AuditUpdateEventListener : IPreUpdateEventListener
{
public bool OnPreUpdate(PreUpdateEvent #event)
{
var audit = #event.Entity as IAuditable;
if (audit == null)
return false;
var lastModifiedOn = DateTime.Now.AddSeconds(28);
var lastModifiedBy = loggedOnProfile;
AuditCommon.Set(#event.Persister, #event.State, "LastModifiedOn", lastModifiedOn);
AuditCommon.Set(#event.Persister, #event.State, "LastModifiedBy", lastModifiedBy);
audit.LastModifiedOn = lastModifiedOn;
audit.LastModifiedBy = lastModifiedBy;
return false;
}
}
}
Code:
using (var session = SessionFactory.OpenSession())
using (var transaction = session.BeginTransaction())
{
var category = session.Query<Category>().First();
category.Name = "Updated";
session.SaveOrUpdate(category);
transaction.Commit();
}
An observation: if I manually update just one of the AuditableEntity properties before calling SaveOrUpdate, the PreUpdate event is obviously fired and appropriate data changes are made, and then the AuditableEntity data IS persisted to the database.
using (var session = SessionFactory.OpenSession())
using (var transaction = session.BeginTransaction())
{
var category = session.Query<Category>().First();
category.Name = "Updated";
category.CreatedOn = DateTime.Now;
session.SaveOrUpdate(category);
transaction.Commit();
}
Help: I obviously don't want to have to dummy edit an AuditableEntity properties, so any ideas as to what I am doing wrong here?
To answer this I have authored an nhibernate.info WIKI article - http://nhibernate.info/doc/howto/various/changing-values-in-nhibernate-events
The abstract; Audit trails using NHibernate's event model often use the OnPreInsert and OnPreUpdate event listeners to change/ modify the state of the entity. While this does works and is widely documented as a solution, it should be noted the OnPreInsert and OnPreUpdate events are not intended to be used to change the values of the entity and instead they should be used to check values and for that reason they return "veto".
An update blog post from Fabio - http://fabiomaulo.blogspot.com/2011/05/nhibernate-bizarre-audit.html

How do I implement ChangeTime and ChangeUser columns using NHibernate?

I'm trying to use NHibernate with an existing database. In the data-model there is columns in each table that contains the time and username of the last update made to a row. How do I do this using NHibernate?
I tried to implement a interceptor that sets ChangeTime and ChangeUser in the entities before it gets saved using the IInterceptor.OnSave method. This didn't work because setting these properties triggers an update to the row even if no other properties has been modified.
It could have worked if there was any way to tell NHibernate to exclude the ChangeTime and ChangeUser properties then it does it's dirty-checking. But i haven't found any way to accomplish this.
Thanks for any help.
You should register a listener to the pre insert and pre update events. You can do it through your configuration like so:
<hibernate-configuration>
...
<event type="pre-update">
<listener class="MyListener, MyAssembly"/>
</event>
<event type="pre-insert">
<listener class="MyListener, MyAssembly"/>
</event>
</hibernate-configuration>
and then implement a listener - something like this (might not be entirely accurate - written off my memory):
public class MyListener : IPreUpdateEventListener, IPreInsertEventListener
{
public bool OnPreUpdate(PreUpdateEvent evt)
{
if (evt.Entity is IHasLastModified)
UpdateLastModified(evt.State, evt.Persister.PropertyNames);
return false;
}
public bool OnPreInsert(PreInsertEvent evt)
{
if (evt.Entity is IHasLastModified)
UpdateLastModified(evt.State, evt.Persister.PropertyNames);
return false;
}
void UpdateLastModified(object[] state, string[] names)
{
var index = Array.FindIndex(names, n => n == "LastModified");
state[index] = DateTime.Now;
}
}
and do the same thing with the pre update event.
EDIT: This one takes care of insert as well as update and it seems to work.
Hey I just had to solve this on a project I am working on, here is my answer
public interface IDateModified
{
DateTime Created { get; set; }
DateTime Modified { get; set; }
}
public class CustomDefaultSaveOrUpdateEventListener
: DefaultSaveOrUpdateEventListener
{
protected override object EntityIsPersistent(SaveOrUpdateEvent evt)
{
var entity = evt.Entity as IDateModified;
if (entity != null)
{
entity.Modified = DateTime.Now;
}
return base.EntityIsPersistent(evt);
}
protected override object EntityIsTransient(SaveOrUpdateEvent evt)
{
var entity = evt.Entity as IDateModified;
if (entity != null)
{
entity.Created = entity.Modified = DateTime.Now;
}
return base.EntityIsTransient(evt);
}
}
Then in my configuration (I am using Fluent NHibernate to configure my unit tests in code)
configuration.EventListeners.SaveOrUpdateEventListeners
= new ISaveOrUpdateEventListener[]
{
new CustomDefaultSaveOrUpdateEventListener()
};
AWESOMENESSSSSSSS!
Mookid's answer is correct although I would like to point out that if one is using S#arp Architecture, the NHib configuration should be set up as follows:
<hibernate-configuration>
<session-factory>
...
<event type="pre-update">
<listener class="MyListener, MyAssembly"/>
</event>
<event type="pre-insert">
<listener class="MyListener, MyAssembly"/>
</event>
</session-factory>
</hibernate-configuration>
The event elements go into the session-factory element.
Instead of using LIsteners, you can also use Interceptors:
Audit changes using interceptor