Re: svn commit: r664536 [1/4]...EventHandler/EventArgs?
I haven't had time yesterday...I will do that today -- Cheers, Gilles
Re: svn commit: r664536 [1/4]...EventHandler/EventArgs?
There's still some other interfaces that need changed over? IResultMapEventListener and IResultPropertyEventListener? - Original Message From: Gilles Bayon <[EMAIL PROTECTED]> To: dev@ibatis.apache.org Sent: Monday, June 9, 2008 12:57:19 PM Subject: Re: svn commit: r664536 [1/4]...EventHandler/EventArgs? I liked it too, will changed to -- Cheers, Gilles
Re: svn commit: r664536 [1/4]...EventHandler/EventArgs?
I liked it too, will changed to -- Cheers, Gilles
Re: svn commit: r664536 [1/4]...EventHandler/EventArgs?
I don't think you need to actually call GetInvocationList since the delegates are all combined to appear as a single item: // TODO: change this over to use generics protected virtual object RaisePreInsert(object parameterObject, object resultObject) { EventHandler handlers = (EventHandler)events[PreInsertEvent]; StatementEventArgs eventArgs = new StatementEventArgs(); eventArgs.MappedStatement = this; eventArgs.ResultObject = resultObject; eventArgs.ParameterObject = parameterObject; // should process _all_ the listeners handlers(this, eventArgs); return eventArgs.ResultObject; } - Original Message From: Ron Grabowski <[EMAIL PROTECTED]> To: dev@ibatis.apache.org Sent: Monday, June 9, 2008 12:40:50 PM Subject: Re: svn commit: r664536 [1/4]...EventHandler/EventArgs? Delegates are only fire and forget if you BeginInvoke them...this is a sequential implementation: // TODO: change this over to use generics protected virtual object RaisePreInsert(object parameterObject, object resultObject) { EventHandler handlers = (EventHandler)events[PreInsertEvent]; StatementEventArgs eventArgs = new StatementEventArgs(); eventArgs.MappedStatement = this; eventArgs.ResultObject = resultObject; eventArgs.ParameterObject = parameterObject; foreach (EventHandler handler in handlers.GetInvocationList()) { handler.Invoke(this, eventArgs); } return eventArgs.ResultObject; } Each subscriber should be able to update/change/proxy ResultObject before its returned: mappedStatement.PreInsert += (s, e) => { ((User)e.ResultObject).CreatedDate = DateTime.Now ; } mappedStatement.PreInsert += (s, e) => { e.ResultObject = createProxy((User)e.ResultObject); } - Original Message From: Gilles Bayon <[EMAIL PROTECTED]> To: dev@ibatis.apache.org Sent: Monday, June 9, 2008 2:20:20 AM Subject: Re: svn commit: r664536 [1/4]...EventHandler/EventArgs? The .NET event pattern cannot be used here, it follows the pattern fire and forget, and it's not what I'm searching as I want to be able to interact with the DataMapper workflow engine, you must see them as extension point where you can change the items that the engine is working on. It can be used for all sorts of cross-cutting concerns Example, replace the resultMap object instance by a proxy one, add/change arguments used by the constructor in the resultMap... private class MyPreCreateEventListener : PreCreateEventListener { /// /// Calls before creating an instance of the object. /// /// The event. /// /// Returns is used as constructor arguments for the instance being created /// public override object OnEvent(PreCreateEvent evnt) { evnt.Parameters[evnt.Parameters.Length-1] = "new lastName"; return evnt.Parameters; } } Example private class MyPreInsertEventListener :PreInsertEventListener { /// /// Calls on the specified event. /// /// The event. /// Returns is used as the parameter object public override object OnEvent(PreInsertEvent evnt) { IDomain domain = evnt.ParameterObject as IDomain; if (domain != null) { ProcessBeforeInsert(domain); } return account; } private void ProcessBeforeInsert(IDomain domain) { User user = (User) Thread.CurrentPrincipal; domain.CreatedBy = user.UserName; domain.ModifiedBy = user.UserName; domain.CreatedDate = DateTime.Now; domain.ModifiedDate = DateTime.Now; } } -- Cheers, Gilles
Re: svn commit: r664536 [1/4]...EventHandler/EventArgs?
Delegates are only fire and forget if you BeginInvoke them...this is a sequential implementation: // TODO: change this over to use generics protected virtual object RaisePreInsert(object parameterObject, object resultObject) { EventHandler handlers = (EventHandler)events[PreInsertEvent]; StatementEventArgs eventArgs = new StatementEventArgs(); eventArgs.MappedStatement = this; eventArgs.ResultObject = resultObject; eventArgs.ParameterObject = parameterObject; foreach (EventHandler handler in handlers.GetInvocationList()) { handler.Invoke(this, eventArgs); } return eventArgs.ResultObject; } Each subscriber should be able to update/change/proxy ResultObject before its returned: mappedStatement.PreInsert += (s, e) => { ((User)e.ResultObject).CreatedDate = DateTime.Now ; } mappedStatement.PreInsert += (s, e) => { e.ResultObject = createProxy((User)e.ResultObject); } - Original Message From: Gilles Bayon <[EMAIL PROTECTED]> To: dev@ibatis.apache.org Sent: Monday, June 9, 2008 2:20:20 AM Subject: Re: svn commit: r664536 [1/4]...EventHandler/EventArgs? The .NET event pattern cannot be used here, it follows the pattern fire and forget, and it's not what I'm searching as I want to be able to interact with the DataMapper workflow engine, you must see them as extension point where you can change the items that the engine is working on. It can be used for all sorts of cross-cutting concerns Example, replace the resultMap object instance by a proxy one, add/change arguments used by the constructor in the resultMap... private class MyPreCreateEventListener : PreCreateEventListener { /// /// Calls before creating an instance of the object. /// /// The event. /// /// Returns is used as constructor arguments for the instance being created /// public override object OnEvent(PreCreateEvent evnt) { evnt.Parameters[evnt.Parameters.Length-1] = "new lastName"; return evnt.Parameters; } } Example private class MyPreInsertEventListener :PreInsertEventListener { /// /// Calls on the specified event. /// /// The event. /// Returns is used as the parameter object public override object OnEvent(PreInsertEvent evnt) { IDomain domain = evnt.ParameterObject as IDomain; if (domain != null) { ProcessBeforeInsert(domain); } return account; } private void ProcessBeforeInsert(IDomain domain) { User user = (User) Thread.CurrentPrincipal; domain.CreatedBy = user.UserName; domain.ModifiedBy = user.UserName; domain.CreatedDate = DateTime.Now; domain.ModifiedDate = DateTime.Now; } } -- Cheers, Gilles
Re: svn commit: r664536 [1/4]...EventHandler/EventArgs?
The .NET event pattern cannot be used here, it follows the pattern fire and forget, and it's not what I'm searching as I want to be able to interact with the DataMapper workflow engine, you must see them as extension point where you can change the items that the engine is working on. It can be used for all sorts of cross-cutting concerns Example, replace the resultMap object instance by a proxy one, add/change arguments used by the constructor in the resultMap... private class MyPreCreateEventListener : PreCreateEventListener { /// /// Calls before creating an instance of the object. /// /// The event. /// /// Returns is used as constructor arguments for the instance being created /// public override object OnEvent(PreCreateEvent evnt) { evnt.Parameters[evnt.Parameters.Length-1] = "new lastName"; return evnt.Parameters; } } Example private class MyPreInsertEventListener :PreInsertEventListener { /// /// Calls on the specified event. /// /// The event. /// Returns is used as the parameter object public override object OnEvent(PreInsertEvent evnt) { IDomain domain = evnt.ParameterObject as IDomain; if (domain != null) { ProcessBeforeInsert(domain); } return account; } private void ProcessBeforeInsert(IDomain domain) { User user = (User) Thread.CurrentPrincipal; domain.CreatedBy = user.UserName; domain.ModifiedBy = user.UserName; domain.CreatedDate = DateTime.Now; domain.ModifiedDate = DateTime.Now; } } -- Cheers, Gilles
Re: svn commit: r664536 [1/4]...EventHandler/EventArgs?
Don't most (all?) events in .NET follow the EventHandler/EventArgs pattern: public class StatementEventArgs : EventArgs { public IMappedStatement MappedStatement; public StatementEventType Type; public object ParameterObject; public object Result; } public interface IMappedStatementEvents { event EventHandler PreInsert; event EventHandler PreSelect; event EventHandler PreUpdateOrDelete; event EventHandler PostInsert; event EventHandler PostSelect; event EventHandler PostUpdateOrDelete; } // Castle.MicroKernel.KernelEventSupport public class MappedStatementEventSupport : IMappedStatementEvents { private static readonly object PreInsertEvent = new object(); // snip private EventHandlerList events = new EventHandlerList(); public event EventHandler PreInsert { add { events.AddHandler(PreInsertEvent, value); } remove { events.RemoveHandler(PreInsertEvent, value); } } protected virtual object RaisePreInsert(IMappedStatement mappedStatement, object parameterObject) { EventHandler handler = (EventHandler) events[PreInsertEvent]; // TODO: create StatementEventArgs and Invoke each item in handler.GetInvocationList() } // snip } public class MappedStatement : MappedStatementEventSupport, IMappedStatement { // add calls to raise events: RaisePreInsert(mappedStatement, parameterObject); } Is there a reason why we rolled our own? I like this: mappedStatement.PreInsert += (s, e) => { Console.WriteLine(e.MappedStatement.Id); } This seems like a lot of code just to register MyConsoleWriter: // ??? PreInsetEventListener[] preInsertEvents = new PreInsetEventListener[mappedStatement.PreInsertListeners.Length + 1]; mappedStatement.PreInsetEventListener.CopyTo(preInsertEvents, 0); preInsertEvents.SetValue( new MyConsoleWriter(), mappedStatement.PreInsetEventListener.Length); mappedStatement.PreInsetEventListener = preInsertEvents; Maybe the listeners should be exposed as System.Collection.Generic.ICollection: mappedStatement.PreInsetEventListener.Add(new MyConsoleWriter()); Also note that I had to write my own class, MyConsoleWriter, instead of just the short lambda expression. The standard EventHandler/EventArgs model makes the most sense to me. - Original Message From: "[EMAIL PROTECTED]" <[EMAIL PROTECTED]> To: [EMAIL PROTECTED] Sent: Sunday, June 8, 2008 2:20:46 PM Subject: svn commit: r664536 [1/4] - in /ibatis/trunk/cs/V3/src: Apache.Ibatis.DataMapper.SqlClient.Test.2005/ Apache.Ibatis.DataMapper.SqlClient.Test.2005/Fixtures/ Apache.Ibatis.DataMapper.SqlClient.Test.2005/Fixtures/Mapping/ Apache.Ibatis.DataMapper.SqlClie... Author: gbayon Date: Sun Jun 8 11:20:44 2008 New Revision: 664536 URL: http://svn.apache.org/viewvc?rev=664536&view=rev Log: IBATISNET-271 add event support Added: ibatis/trunk/cs/V3/src/Apache.Ibatis.DataMapper.SqlClient.Test.2005/Fixtures/Mapping/EventTest.cs (with props) ibatis/trunk/cs/V3/src/Apache.Ibatis.DataMapper.SqlClient.Test.2005/Fixtures/Modules/EventModule.cs (with props) ibatis/trunk/cs/V3/src/Apache.Ibatis.DataMapper.SqlClient.Test.2005/Fixtures/ScriptBase.cs (with props) ibatis/trunk/cs/V3/src/Apache.Ibatis.DataMapper.SqlClient.Test.2005/Maps/Event.xml ibatis/trunk/cs/V3/src/Apache.Ibatis.DataMapper.SqlClient.Test.2005/bin/Debug/SqlMap.event.config ibatis/trunk/cs/V3/src/Apache.Ibatis.DataMapper/DataMapperLocalSessionScope.cs (with props) ibatis/trunk/cs/V3/src/Apache.Ibatis.DataMapper/Model/Events/ [snip]