Commit 0fa9e1c

mo khan <mo@mokhan.ca>
2010-02-08 05:30:44
trying to figure out a clever way to run queries within a unit of work.
1 parent 71664b8
build/lib/app/automapper/AutoMapper.dll
Binary file
product/client/presentation.windows/bootstrappers/Bootstrapper.cs
@@ -1,3 +1,4 @@
+using System;
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.IO;
@@ -17,10 +18,12 @@ using NHibernate.ByteCode.Castle;
 using NHibernate.Cfg;
 using NHibernate.Tool.hbm2ddl;
 using presentation.windows.commands;
+using presentation.windows.infrastructure;
 using presentation.windows.orm;
 using presentation.windows.orm.mappings;
 using presentation.windows.orm.nhibernate;
 using presentation.windows.presenters;
+using presentation.windows.queries;
 using presentation.windows.views;
 using Environment = System.Environment;
 using ISession = NHibernate.ISession;
@@ -39,14 +42,15 @@ namespace presentation.windows.bootstrappers
 
             //needs startups
             builder.Register<ComposeShell>().As<NeedStartup>();
+            builder.Register<ConfigureMappings>().As<NeedStartup>();
 
             // infrastructure
             builder.Register<Log4NetLogFactory>().As<LogFactory>().SingletonScoped();
-
+            builder.Register<DefaultMapper>().As<Mapper>().SingletonScoped();
 
             var session_factory = bootstrap_nhibernate();
             builder.Register(x => session_factory).SingletonScoped();
-            builder.Register(x => x.Resolve<IContext>().value_for(new momoney.database.transactions.TypedKey<ISession>()));
+            builder.Register(x => x.Resolve<IContext>().value_for(new TypedKey<ISession>()));
             builder.Register<NHibernateUnitOfWorkFactory>().As<IUnitOfWorkFactory>();
             builder.Register(x => new ContextFactory().create_for(new PerThreadScopedStorage(new CurrentThread())));
 
@@ -67,6 +71,11 @@ namespace presentation.windows.bootstrappers
             builder.Register<AsynchronousCommandProcessor>().As<CommandProcessor>().SingletonScoped();
             builder.Register<AddFamilyMemberCommand>();
 
+            // queries
+            builder.Register<FindMemberIdentifiedBy>();
+            builder.Register<FindAllFamily>();
+            builder.Register<ContainerAwareQueryBuilder>().As<QueryBuilder>();
+
             // repositories
             builder.Register<NHibernatePersonRepository>().As<PersonRepository>();
 
product/client/presentation.windows/bootstrappers/ConfigureMappings.cs
@@ -0,0 +1,21 @@
+using AutoMapper;
+using presentation.windows.domain;
+using presentation.windows.queries;
+
+namespace presentation.windows.bootstrappers
+{
+    public class ConfigureMappings : NeedStartup
+    {
+        public void run()
+        {
+            Mapper
+                .CreateMap<Person, PersonDetails>()
+                .ConvertUsing(x => new PersonDetails
+                                   {
+                                       id = x.id,
+                                       first_name = x.first_name,
+                                       last_name = x.last_name,
+                                   });
+        }
+    }
+}
\ No newline at end of file
product/client/presentation.windows/commands/AddFamilyMemberCommand.cs
@@ -22,9 +22,10 @@ namespace presentation.windows.commands
         {
             var person = Person.New(item.first_name, item.last_name, item.date_of_birth);
             people.save(person);
-            event_aggregator.publish(new SelectedFamilyMember
+            event_aggregator.publish(new AddedNewFamilyMember
                                      {
                                          id = person.id,
+                                         first_name = person.first_name,
                                      });
         }
     }
product/client/presentation.windows/commands/ContainerAwareParameterizedCommandBuilder.cs
@@ -1,12 +1,8 @@
 using System;
 using Gorilla.Commons.Infrastructure.Container;
 using gorilla.commons.utility;
-using momoney.database.transactions;
 using MoMoney.Service.Infrastructure.Eventing;
 using momoney.service.infrastructure.transactions;
-using ISession = NHibernate.ISession;
-using ISessionFactory = NHibernate.ISessionFactory;
-using ITransaction = NHibernate.ITransaction;
 
 namespace presentation.windows.commands
 {
@@ -53,57 +49,4 @@ namespace presentation.windows.commands
             }
         }
     }
-
-    public class NHibernateUnitOfWorkFactory : IUnitOfWorkFactory
-    {
-        readonly ISessionFactory factory;
-        readonly IContext context;
-
-        public NHibernateUnitOfWorkFactory(ISessionFactory factory, IContext context)
-        {
-            this.factory = factory;
-            this.context = context;
-        }
-
-        public IUnitOfWork create()
-        {
-            var open_session = factory.OpenSession();
-            context.add(new TypedKey<ISession>(), open_session);
-            return new NHibernateUnitOfWork(open_session, context);
-        }
-    }
-
-    public class NHibernateUnitOfWork : IUnitOfWork
-    {
-        readonly ISession session;
-        readonly IContext context;
-        ITransaction transaction;
-
-        public NHibernateUnitOfWork(ISession session, IContext context)
-        {
-            this.session = session;
-            this.context = context;
-            transaction = session.BeginTransaction();
-        }
-
-        public void Dispose()
-        {
-            if (!transaction.WasCommitted && !transaction.WasRolledBack)
-            {
-                transaction.Rollback();
-            }
-            session.Dispose();
-            context.remove(new TypedKey<ISession>());
-        }
-
-        public void commit()
-        {
-            if (is_dirty()) transaction.Commit();
-        }
-
-        public bool is_dirty()
-        {
-            return session.IsDirty();
-        }
-    }
 }
\ No newline at end of file
product/client/presentation.windows/domain/Entity.cs
@@ -1,10 +1,16 @@
 using System;
+using gorilla.commons.utility;
 
 namespace presentation.windows.domain
 {
     public class Entity : IEquatable<Entity>
     {
-        public virtual Guid id { get; set; }
+        protected Entity()
+        {
+            id = Id<Guid>.Default;
+        }
+
+        public virtual Guid id { get; private set; }
 
         public virtual bool Equals(Entity other)
         {
product/client/presentation.windows/events/SelectedFamilyMember.cs โ†’ product/client/presentation.windows/events/AddedNewFamilyMember.cs
@@ -3,8 +3,10 @@ using MoMoney.Service.Infrastructure.Eventing;
 
 namespace presentation.windows.events
 {
-    public class SelectedFamilyMember : IEvent
+    public class AddedNewFamilyMember : IEvent
     {
         public Guid id { get; set; }
+
+        public string first_name { get; set; }
     }
 }
\ No newline at end of file
product/client/presentation.windows/infrastructure/AnonymousInterceptor.cs
@@ -0,0 +1,20 @@
+using System;
+using Castle.Core.Interceptor;
+
+namespace presentation.windows.infrastructure
+{
+    public class AnonymousInterceptor : IInterceptor
+    {
+        Action<IInvocation> interceptor;
+
+        public AnonymousInterceptor(Action<IInvocation> interceptor)
+        {
+            this.interceptor = interceptor;
+        }
+
+        public void Intercept(IInvocation invocation)
+        {
+            interceptor(invocation);
+        }
+    }
+}
\ No newline at end of file
product/client/presentation.windows/infrastructure/DefaultMapper.cs
@@ -0,0 +1,12 @@
+using gorilla.commons.utility;
+
+namespace presentation.windows.infrastructure
+{
+    public class DefaultMapper : Mapper
+    {
+        public Output map_from<Input, Output>(Input item)
+        {
+            return AutoMapper.Mapper.Map<Input, Output>(item);
+        }
+    }
+}
\ No newline at end of file
product/client/presentation.windows/orm/nhibernate/NHibernatePersonRepository.cs
@@ -1,4 +1,8 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
 using NHibernate;
+using NHibernate.Linq;
 using presentation.windows.domain;
 
 namespace presentation.windows.orm.nhibernate
@@ -16,5 +20,15 @@ namespace presentation.windows.orm.nhibernate
         {
             session.Save(person);
         }
+
+        public Person find_by(Guid id)
+        {
+            return session.Linq<Person>().Single(x => x.id.Equals(id));
+        }
+
+        public IEnumerable<Person> find_all()
+        {
+            return session.Linq<Person>().ToList();
+        }
     }
 }
\ No newline at end of file
product/client/presentation.windows/orm/nhibernate/NHibernateUnitOfWork.cs
@@ -0,0 +1,41 @@
+using momoney.database.transactions;
+using momoney.service.infrastructure.transactions;
+using ISession = NHibernate.ISession;
+using ITransaction = NHibernate.ITransaction;
+
+namespace presentation.windows.orm.nhibernate
+{
+    public class NHibernateUnitOfWork : IUnitOfWork
+    {
+        readonly ISession session;
+        readonly IContext context;
+        ITransaction transaction;
+
+        public NHibernateUnitOfWork(ISession session, IContext context)
+        {
+            this.session = session;
+            this.context = context;
+            transaction = session.BeginTransaction();
+        }
+
+        public void Dispose()
+        {
+            if (!transaction.WasCommitted && !transaction.WasRolledBack)
+            {
+                transaction.Rollback();
+            }
+            session.Dispose();
+            context.remove(new TypedKey<ISession>());
+        }
+
+        public void commit()
+        {
+            if (is_dirty()) transaction.Commit();
+        }
+
+        public bool is_dirty()
+        {
+            return session.IsDirty();
+        }
+    }
+}
\ No newline at end of file
product/client/presentation.windows/orm/nhibernate/NHibernateUnitOfWorkFactory.cs
@@ -0,0 +1,26 @@
+using momoney.database.transactions;
+using momoney.service.infrastructure.transactions;
+using ISession = NHibernate.ISession;
+using ISessionFactory = NHibernate.ISessionFactory;
+
+namespace presentation.windows.orm.nhibernate
+{
+    public class NHibernateUnitOfWorkFactory : IUnitOfWorkFactory
+    {
+        readonly ISessionFactory factory;
+        readonly IContext context;
+
+        public NHibernateUnitOfWorkFactory(ISessionFactory factory, IContext context)
+        {
+            this.factory = factory;
+            this.context = context;
+        }
+
+        public IUnitOfWork create()
+        {
+            var open_session = factory.OpenSession();
+            context.add(new TypedKey<ISession>(), open_session);
+            return new NHibernateUnitOfWork(open_session, context);
+        }
+    }
+}
\ No newline at end of file
product/client/presentation.windows/orm/PersonRepository.cs
@@ -1,3 +1,5 @@
+using System;
+using System.Collections.Generic;
 using presentation.windows.domain;
 
 namespace presentation.windows.orm
@@ -5,5 +7,7 @@ namespace presentation.windows.orm
     public interface PersonRepository
     {
         void save(Person person);
+        Person find_by(Guid id);
+        IEnumerable<Person> find_all();
     }
 }
\ No newline at end of file
product/client/presentation.windows/presenters/SelectedFamilyMemberPresenter.cs
@@ -1,12 +1,47 @@
+using System.Collections.Generic;
+using System.Linq;
 using MoMoney.Service.Infrastructure.Eventing;
 using presentation.windows.events;
+using presentation.windows.queries;
 
 namespace presentation.windows.presenters
 {
-    public class SelectedFamilyMemberPresenter : Observable<SelectedFamilyMemberPresenter>, Presenter, EventSubscriber<SelectedFamilyMember>
+    public class SelectedFamilyMemberPresenter : Observable<SelectedFamilyMemberPresenter>, Presenter, EventSubscriber<AddedNewFamilyMember>
     {
-        public void present() {}
+        PersonDetails selected_member;
+        QueryBuilder builder;
 
-        public void notify(SelectedFamilyMember message) {}
+        public SelectedFamilyMemberPresenter(QueryBuilder builder)
+        {
+            this.builder = builder;
+        }
+
+        public string first_name { get; set; }
+        public string last_name { get; set; }
+        public IList<PersonDetails> family_members { get; set; }
+
+        public PersonDetails SelectedMember
+        {
+            get { return selected_member; }
+            set
+            {
+                selected_member = value;
+                first_name = selected_member.first_name;
+                last_name = selected_member.last_name;
+                update(x => x.first_name, x => x.last_name);
+            }
+        }
+
+        public void present()
+        {
+            family_members = builder.build<FindAllFamily>().fetch().ToList();
+            update(x => x.family_members);
+        }
+
+        public void notify(AddedNewFamilyMember message)
+        {
+            family_members.Add(builder.build<FindMemberIdentifiedBy>().fetch(message.id));
+            update(x => x.family_members);
+        }
     }
 }
\ No newline at end of file
product/client/presentation.windows/queries/ContainerAwareQueryBuilder.cs
@@ -0,0 +1,36 @@
+using Castle.DynamicProxy;
+using momoney.service.infrastructure.transactions;
+using presentation.windows.infrastructure;
+
+namespace presentation.windows.queries
+{
+    public class ContainerAwareQueryBuilder : QueryBuilder
+    {
+        IUnitOfWorkFactory factory;
+        ProxyGenerator generator;
+        AnonymousInterceptor anonymous_interceptor;
+
+        public ContainerAwareQueryBuilder(IUnitOfWorkFactory factory)
+        {
+            this.factory = factory;
+            generator = new ProxyGenerator();
+            anonymous_interceptor = new AnonymousInterceptor(x =>
+            {
+                using (var unit_of_work = factory.create())
+                {
+                    x.Proceed();
+                    unit_of_work.commit();
+                }
+            });
+        }
+
+        public Query build<Query>() where Query : class
+        {
+            return generator.CreateClassProxy<Query>(anonymous_interceptor);
+
+            //var proxy_builder = new CastleDynamicProxyBuilder<Query>();
+            //proxy_builder.add_interceptor(anonymous_interceptor);
+            //return proxy_builder.create_proxy_for(Resolve.the<Query>());
+        }
+    }
+}
\ No newline at end of file
product/client/presentation.windows/queries/FindAllFamily.cs
@@ -0,0 +1,24 @@
+using System.Collections.Generic;
+using gorilla.commons.utility;
+using presentation.windows.domain;
+using presentation.windows.orm;
+
+namespace presentation.windows.queries
+{
+    public class FindAllFamily : Query<IEnumerable<PersonDetails>>
+    {
+        PersonRepository people;
+        Mapper mapper;
+
+        public FindAllFamily(PersonRepository people, Mapper mapper)
+        {
+            this.people = people;
+            this.mapper = mapper;
+        }
+
+        public IEnumerable<PersonDetails> fetch()
+        {
+            return people.find_all().map_all_using<Person, PersonDetails>(mapper);
+        }
+    }
+}
\ No newline at end of file
product/client/presentation.windows/queries/FindMemberIdentifiedBy.cs
@@ -0,0 +1,24 @@
+using System;
+using gorilla.commons.utility;
+using presentation.windows.domain;
+using presentation.windows.orm;
+
+namespace presentation.windows.queries
+{
+    public class FindMemberIdentifiedBy : Query<Guid, PersonDetails>
+    {
+        PersonRepository people;
+        Mapper mapper;
+
+        public FindMemberIdentifiedBy(PersonRepository people, Mapper mapper)
+        {
+            this.people = people;
+            this.mapper = mapper;
+        }
+
+        public PersonDetails fetch(Guid item)
+        {
+            return people.find_by(item).map_using<Person, PersonDetails>(mapper);
+        }
+    }
+}
\ No newline at end of file
product/client/presentation.windows/queries/PersonDetails.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace presentation.windows.queries
+{
+    public class PersonDetails
+    {
+        public Guid id { get; set; }
+
+        public string first_name { get; set; }
+
+        public string last_name { get; set; }
+    }
+}
\ No newline at end of file
product/client/presentation.windows/queries/QueryBuilder.cs
@@ -0,0 +1,7 @@
+namespace presentation.windows.queries
+{
+    public interface QueryBuilder
+    {
+        Query build<Query>() where Query : class;
+    }
+}
\ No newline at end of file
product/client/presentation.windows/views/SelectedFamilyMemberRegion.xaml
@@ -5,14 +5,14 @@
     <Expander.Header>
         <DockPanel>
         <Label>Family Member:</Label>
-        <ComboBox Width="150"></ComboBox>
+        <ComboBox ItemsSource="{Binding family_members}" SelectedItem="{Binding selected_member}" Width="150"></ComboBox>
         </DockPanel>
     </Expander.Header>
     <UniformGrid>
         <Label FontWeight="Bold">First Name</Label>
-        <Label>Mo</Label>
+        <Label Content="{Binding fist_name}"/>
         <Label FontWeight="Bold">Last Name</Label>
-        <Label>Khan</Label>
+        <Label Content="{Binding last_name}"/>
     </UniformGrid>
 </Expander>
 </UserControl>
product/client/presentation.windows/presentation.windows.csproj
@@ -38,6 +38,18 @@
       <SpecificVersion>False</SpecificVersion>
       <HintPath>..\..\..\build\lib\app\auto.fac\Autofac.dll</HintPath>
     </Reference>
+    <Reference Include="AutoMapper, Version=0.3.1.71, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\build\lib\app\automapper\AutoMapper.dll</HintPath>
+    </Reference>
+    <Reference Include="Castle.Core, Version=1.1.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\build\lib\app\nhibernate\Castle.Core.dll</HintPath>
+    </Reference>
+    <Reference Include="Castle.DynamicProxy2, Version=2.1.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\build\lib\app\nhibernate\Castle.DynamicProxy2.dll</HintPath>
+    </Reference>
     <Reference Include="FluentNHibernate, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8aa435e3cb308880, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
       <HintPath>..\..\..\build\lib\app\nhibernate\FluentNHibernate.dll</HintPath>
@@ -50,6 +62,10 @@
       <SpecificVersion>False</SpecificVersion>
       <HintPath>..\..\..\build\lib\app\nhibernate\NHibernate.ByteCode.Castle.dll</HintPath>
     </Reference>
+    <Reference Include="NHibernate.Linq, Version=1.0.0.4000, Culture=neutral, PublicKeyToken=444cf6a87fdab271, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\build\lib\app\nhibernate\NHibernate.Linq.dll</HintPath>
+    </Reference>
     <Reference Include="System" />
     <Reference Include="System.Core">
       <RequiredTargetFramework>3.5</RequiredTargetFramework>
@@ -113,9 +129,13 @@
   <ItemGroup>
     <Compile Include="ApplicationController.cs" />
     <Compile Include="bootstrappers\Bootstrapper.cs" />
+    <Compile Include="bootstrappers\ConfigureMappings.cs" />
+    <Compile Include="orm\nhibernate\NHibernateUnitOfWorkFactory.cs" />
+    <Compile Include="orm\nhibernate\NHibernateUnitOfWork.cs" />
+    <Compile Include="infrastructure\DefaultMapper.cs" />
     <Compile Include="commands\ParameterizedCommandBuilder.cs" />
     <Compile Include="domain\Entity.cs" />
-    <Compile Include="events\SelectedFamilyMember.cs" />
+    <Compile Include="events\AddedNewFamilyMember.cs" />
     <Compile Include="commands\UpdateOnLongRunningProcess.cs" />
     <Compile Include="Dialog.cs" />
     <Compile Include="DialogPresenter.cs" />
@@ -128,14 +148,20 @@
     <Compile Include="presenters\AddFamilyMemberPresenter.cs" />
     <Compile Include="commands\CommandBuilder.cs" />
     <Compile Include="commands\AddFamilyMemberCommand.cs" />
+    <Compile Include="infrastructure\AnonymousInterceptor.cs" />
     <Compile Include="presenters\CompensationPresenter.cs" />
     <Compile Include="commands\dto\FamilyMemberToAdd.cs" />
     <Compile Include="commands\ContainerCommandBuilder.cs" />
     <Compile Include="commands\NamedCommand.cs" />
     <Compile Include="commands\ContainerAwareParameterizedCommandBuilder.cs" />
+    <Compile Include="queries\ContainerAwareQueryBuilder.cs" />
+    <Compile Include="queries\FindAllFamily.cs" />
+    <Compile Include="queries\FindMemberIdentifiedBy.cs" />
     <Compile Include="presenters\SelectedFamilyMemberPresenter.cs" />
     <Compile Include="presenters\StatusBarPresenter.cs" />
     <Compile Include="presenters\Observable.cs" />
+    <Compile Include="queries\PersonDetails.cs" />
+    <Compile Include="queries\QueryBuilder.cs" />
     <Compile Include="View.cs" />
     <Compile Include="views\AddFamilyMemberDialog.xaml.cs">
       <DependentUpon>AddFamilyMemberDialog.xaml</DependentUpon>
@@ -206,6 +232,10 @@
       <Project>{DD8FD29E-7424-415C-9BA3-7D9F6ECBA161}</Project>
       <Name>utility</Name>
     </ProjectReference>
+    <ProjectReference Include="..\boot\boot.csproj">
+      <Project>{2DB82691-BF15-4538-8C5E-6BF8F4F875A9}</Project>
+      <Name>boot</Name>
+    </ProjectReference>
     <ProjectReference Include="..\database\database.csproj">
       <Project>{580E68A8-EDEE-4350-8BBE-A053645B0F83}</Project>
       <Name>database</Name>
product/commons/infrastructure.thirdparty/infrastructure.thirdparty.csproj
@@ -75,8 +75,16 @@
     <Compile Include="castle\dynamicproxy\CastleDynamicInterceptorConstraintFactory.cs" />
     <Compile Include="castle\dynamicproxy\interceptors\SynchronizeInvokeInterceptor.cs" />
     <Compile Include="castle\dynamicproxy\CastleDynamicMethodCallTrackerFactory.cs" />
-    <Compile Include="castle\windsor\configuration\RegistrationConfiguration.cs" />
+    <Compile Include="castle\windsor\configuration\ApplyLoggingInterceptor.cs" />
+    <Compile Include="castle\windsor\configuration\ComponentExclusionSpecification.cs" />
+    <Compile Include="castle\windsor\configuration\ComponentRegistrationConfiguration.cs" />
+    <Compile Include="castle\windsor\configuration\ConfigureComponentLifestyle.cs" />
+    <Compile Include="castle\windsor\configuration\LogComponent.cs" />
+    <Compile Include="castle\windsor\configuration\LogEverythingInterceptor.cs" />
     <Compile Include="castle\windsor\configuration\LoggingInterceptor.cs" />
+    <Compile Include="castle\windsor\configuration\RegisterComponentContract.cs" />
+    <Compile Include="castle\windsor\configuration\RegistrationConfiguration.cs" />
+    <Compile Include="castle\windsor\WindsorContainerFactory.cs" />
     <Compile Include="castle\windsor\WindsorExtensions.cs" />
     <Compile Include="DependencyRegistration.cs" />
     <Compile Include="castle\dynamicproxy\ConstraintSelector.cs" />
@@ -92,14 +100,6 @@
     <Compile Include="castle\dynamicproxy\LazyLoadedInterceptor.cs" />
     <Compile Include="castle\dynamicproxy\CastleDynamicProxyBuilder.cs" />
     <Compile Include="castle\dynamicproxy\CastleDynamicProxyFactory.cs" />
-    <Compile Include="castle\windsor\configuration\ApplyLoggingInterceptor.cs" />
-    <Compile Include="castle\windsor\configuration\ComponentRegistrationConfiguration.cs" />
-    <Compile Include="castle\windsor\configuration\ConfigureComponentLifestyle.cs" />
-    <Compile Include="castle\windsor\configuration\ComponentExclusionSpecification.cs" />
-    <Compile Include="castle\windsor\configuration\LogComponent.cs" />
-    <Compile Include="castle\windsor\configuration\LogEverythingInterceptor.cs" />
-    <Compile Include="castle\windsor\configuration\RegisterComponentContract.cs" />
-    <Compile Include="castle\windsor\WindsorContainerFactory.cs" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\infrastructure\infrastructure.csproj">
product/commons/utility/Id.cs
@@ -5,8 +5,8 @@ namespace gorilla.commons.utility
     [Serializable]
     public class Id<T>
     {
-        static public readonly Id<T> Default = new Id<T>(default(T));
-        readonly T id;
+        static public readonly Id<T> Default = new Id<T>(default(T));
+        public T id { get; private set; }
 
         public Id(T id)
         {
product/commons/utility/Mapper.cs
@@ -1,7 +1,12 @@
-namespace gorilla.commons.utility
-{
-    public interface Mapper<Input, Output>
-    {
-        Output map_from(Input item);
-    }
+namespace gorilla.commons.utility
+{
+    public interface Mapper<Input, Output>
+    {
+        Output map_from(Input item);
+    }
+
+    public interface Mapper
+    {
+        Output map_from<Input, Output>(Input item);
+    }
 }
\ No newline at end of file
product/commons/utility/MappingExtensions.cs
@@ -1,37 +1,48 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace gorilla.commons.utility
-{
-    public static class MappingExtensions
-    {
-        public static Output map_using<Input, Output>(this Input item, Converter<Input, Output> conversion)
-        {
-            return conversion(item);
-        }
-
-        public static Output map_using<Input, Output>(this Input item, Mapper<Input, Output> mapper)
-        {
-            return map_using(item, x => mapper.map_from(x));
-        }
-
-        public static IEnumerable<Output> map_all_using<Input, Output>(this IEnumerable<Input> items,
-                                                                       Converter<Input, Output> mapper)
-        {
-            return null == items ? new List<Output>() : items.Select(x => mapper(x));
-        }
-
-        public static IEnumerable<Output> map_all_using<Input, Output>(this IEnumerable<Input> items,
-                                                                       Mapper<Input, Output> mapper)
-        {
-            return map_all_using(items, x => mapper.map_from(x));
-        }
-
-        public static Mapper<Left, Right> then<Left, Middle, Right>(this Mapper<Left, Middle> left,
-                                                                    Mapper<Middle, Right> right)
-        {
-            return new ChainedMapper<Left, Middle, Right>(left, right);
-        }
-    }
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace gorilla.commons.utility
+{
+    static public class MappingExtensions
+    {
+        static public Output map_using<Input, Output>(this Input item, Converter<Input, Output> conversion)
+        {
+            return conversion(item);
+        }
+
+        static public Output map_using<Input, Output>(this Input item, Mapper<Input, Output> mapper)
+        {
+            return map_using(item, x => mapper.map_from(x));
+        }
+
+        static public Output map_using<Input, Output>(this Input item, Mapper mapper)
+        {
+            return map_using(item, x => mapper.map_from<Input, Output>(x));
+        }
+
+        static public IEnumerable<Output> map_all_using<Input, Output>(this IEnumerable<Input> items,
+                                                                       Converter<Input, Output> mapper)
+        {
+            return null == items ? new List<Output>() : items.Select(x => mapper(x));
+        }
+
+        static public IEnumerable<Output> map_all_using<Input, Output>(this IEnumerable<Input> items,
+                                                                       Mapper<Input, Output> mapper)
+        {
+            return map_all_using(items, x => mapper.map_from(x));
+        }
+
+        static public IEnumerable<Output> map_all_using<Input, Output>(this IEnumerable<Input> items,
+                                                                       Mapper mapper)
+        {
+            return map_all_using(items, x => mapper.map_from<Input, Output>(x));
+        }
+
+        static public Mapper<Left, Right> then<Left, Middle, Right>(this Mapper<Left, Middle> left,
+                                                                    Mapper<Middle, Right> right)
+        {
+            return new ChainedMapper<Left, Middle, Right>(left, right);
+        }
+    }
 }
\ No newline at end of file