Commit 126b3fc
Changed files (83)
build
product
MoMoney.DataAccess
Transactions
MoMoney.Domain
Core
MoMoney.Presentation
MoMoney.Service
Application
Infrastructure
MyMoney
boot
container
registration
Modules
build/lib/app/gorilla/gorilla.commons.infrastructure.dll
Binary file
build/lib/app/gorilla/gorilla.commons.infrastructure.thirdparty.dll
Binary file
build/lib/app/gorilla/gorilla.commons.utility.dll
Binary file
build/lib/app/gorilla/gorilla.commons.windows.forms.dll
Binary file
build/lib/app/gorilla/gorilla.commons.windows.forms.thirdparty.dll
Binary file
build/tools/nant/NAnt.exe.config
@@ -481,7 +481,7 @@
hive="LocalMachine" />
<readregistry
property="sdkInstallRoot"
- key="SOFTWARE\Microsoft\Microsoft SDKs\Windows\v6.1\WinSDKNetFxTools\InstallationFolder"
+ key="SOFTWARE\Microsoft\Microsoft SDKs\Windows\v6.0a\WinSDKNetFxTools\InstallationFolder"
hive="LocalMachine"
failonerror="false" />
</project>
build/project.build
@@ -1,5 +1,6 @@
<project name="momoney">
<property name="project.name" value="${project::get-name()}" />
+ <property name="nant.settings.currentframework" value="net-3.5" />
<property name="base.dir" value="${directory::get-parent-directory(project::get-base-directory())}" />
<property name="product.dir" value="${base.dir}\product" />
product/MoMoney.DataAccess/Transactions/ChangeTracker.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Gorilla.Commons.Infrastructure.Transactions;
+using Gorilla.Commons.Utility.Core;
+using Gorilla.Commons.Utility.Extensions;
+
+namespace MoMoney.DataAccess.Transactions
+{
+ public class ChangeTracker<T> : IChangeTracker<T> where T : IIdentifiable<Guid>
+ {
+ readonly ITrackerEntryMapper<T> mapper;
+ readonly IStatementRegistry registry;
+ readonly IList<ITrackerEntry<T>> items;
+ readonly IList<T> to_be_deleted;
+
+ public ChangeTracker(ITrackerEntryMapper<T> mapper, IStatementRegistry registry)
+ {
+ this.mapper = mapper;
+ this.registry = registry;
+ items = new List<ITrackerEntry<T>>();
+ to_be_deleted = new List<T>();
+ }
+
+ public void register(T entity)
+ {
+ items.Add(mapper.map_from(entity));
+ }
+
+ public void delete(T entity)
+ {
+ to_be_deleted.Add(entity);
+ }
+
+ public void commit_to(IDatabase database)
+ {
+ items.each(x => commit(x, database));
+ to_be_deleted.each(x => database.apply(registry.prepare_command_for(x)));
+ }
+
+ public bool is_dirty()
+ {
+ return items.Count(x => x.has_changes()) > 0 || to_be_deleted.Count > 0;
+ }
+
+ public void Dispose()
+ {
+ items.Clear();
+ }
+
+ void commit(ITrackerEntry<T> entry, IDatabase database)
+ {
+ if (entry.has_changes()) database.apply(registry.prepare_command_for(entry.current));
+ }
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/ChangeTrackerFactory.cs
@@ -0,0 +1,24 @@
+using System;
+using Gorilla.Commons.Infrastructure.Container;
+using Gorilla.Commons.Infrastructure.Transactions;
+using Gorilla.Commons.Utility.Core;
+
+namespace MoMoney.DataAccess.Transactions
+{
+ public class ChangeTrackerFactory : IChangeTrackerFactory
+ {
+ readonly IStatementRegistry statement_registry;
+ readonly IDependencyRegistry registry;
+
+ public ChangeTrackerFactory(IStatementRegistry statement_registry, IDependencyRegistry registry)
+ {
+ this.statement_registry = statement_registry;
+ this.registry = registry;
+ }
+
+ public IChangeTracker<T> create_for<T>() where T : IIdentifiable<Guid>
+ {
+ return new ChangeTracker<T>(registry.get_a<ITrackerEntryMapper<T>>(), statement_registry);
+ }
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/ChangeTrackerFactorySpecs.cs
@@ -0,0 +1,22 @@
+using System;
+using developwithpassion.bdd.contexts;
+using Gorilla.Commons.Infrastructure.Transactions;
+using Gorilla.Commons.Testing;
+using Gorilla.Commons.Utility.Core;
+
+namespace MoMoney.DataAccess.Transactions
+{
+ public class ChangeTrackerFactorySpecs
+ {
+ }
+
+ [Concern(typeof (ChangeTrackerFactory))]
+ public class when_creating_a_change_tracker_for_an_item : concerns_for<IChangeTrackerFactory, ChangeTrackerFactory>
+ {
+ it should_return_a_new_tracker = () => result.should_not_be_null();
+
+ because b = () => { result = sut.create_for<IIdentifiable<Guid>>(); };
+
+ static IChangeTracker<IIdentifiable<Guid>> result;
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/ChangeTrackerSpecs.cs
@@ -0,0 +1,104 @@
+using System;
+using developwithpassion.bdd.contexts;
+using Gorilla.Commons.Infrastructure.Transactions;
+using Gorilla.Commons.Testing;
+using Gorilla.Commons.Utility.Core;
+
+namespace MoMoney.DataAccess.Transactions
+{
+ public class ChangeTrackerSpecs
+ {
+ }
+
+ [Concern(typeof (ChangeTracker<IIdentifiable<Guid>>))]
+ public abstract class behaves_like_change_tracker :
+ concerns_for<IChangeTracker<IIdentifiable<Guid>>, ChangeTracker<IIdentifiable<Guid>>>
+ {
+ context c = () =>
+ {
+ mapper = the_dependency<ITrackerEntryMapper<IIdentifiable<Guid>>>();
+ registry = the_dependency<IStatementRegistry>();
+ };
+
+ static protected ITrackerEntryMapper<IIdentifiable<Guid>> mapper;
+ static protected IStatementRegistry registry;
+ }
+
+ [Concern(typeof (ChangeTracker<IIdentifiable<Guid>>))]
+ public class when_commit_that_changes_made_to_an_item : behaves_like_change_tracker
+ {
+ it should_save_the_changes_to_the_database = () => database.was_told_to(x => x.apply(statement));
+
+ context c = () =>
+ {
+ item = an<IIdentifiable<Guid>>();
+ statement = an<IStatement>();
+ database = an<IDatabase>();
+ var entry = an<ITrackerEntry<IIdentifiable<Guid>>>();
+
+ when_the(mapper).is_told_to(x => x.map_from(item)).it_will_return(entry);
+ when_the(entry).is_told_to(x => x.has_changes()).it_will_return(true);
+ when_the(entry).is_told_to(x => x.current).it_will_return(item);
+ when_the(registry).is_told_to(x => x.prepare_command_for(item)).it_will_return(statement);
+ };
+
+ because b = () =>
+ {
+ sut.register(item);
+ sut.commit_to(database);
+ };
+
+ static IIdentifiable<Guid> item;
+ static IDatabase database;
+ static IStatement statement;
+ }
+
+ [Concern(typeof (ChangeTracker<IIdentifiable<Guid>>))]
+ public class when_checking_if_there_are_changes_and_there_are : behaves_like_change_tracker
+ {
+ it should_tell_the_truth = () => result.should_be_true();
+
+ context c = () =>
+ {
+ item = an<IIdentifiable<Guid>>();
+ var registration = an<ITrackerEntry<IIdentifiable<Guid>>>();
+
+ when_the(mapper).is_told_to(x => x.map_from(item)).it_will_return(registration);
+ when_the(registration).is_told_to(x => x.has_changes()).it_will_return(true);
+ when_the(registration).is_told_to(x => x.current).it_will_return(item);
+ };
+
+ because b = () =>
+ {
+ sut.register(item);
+ result = sut.is_dirty();
+ };
+
+ static bool result;
+ static IIdentifiable<Guid> item;
+ }
+
+ [Concern(typeof (ChangeTracker<IIdentifiable<Guid>>))]
+ public class when_checking_if_there_are_changes_and_there_are_not : behaves_like_change_tracker
+ {
+ it should_tell_the_truth = () => result.should_be_false();
+
+ context c = () =>
+ {
+ item = an<IIdentifiable<Guid>>();
+ var entry = an<ITrackerEntry<IIdentifiable<Guid>>>();
+
+ when_the(mapper).is_told_to(x => x.map_from(item)).it_will_return(entry);
+ when_the(entry).is_told_to(x => x.has_changes()).it_will_return(false);
+ };
+
+ because b = () =>
+ {
+ sut.register(item);
+ result = sut.is_dirty();
+ };
+
+ static bool result;
+ static IIdentifiable<Guid> item;
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/Context.cs
@@ -0,0 +1,34 @@
+using System.Collections;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public class Context : IContext
+ {
+ readonly IDictionary items;
+
+ public Context(IDictionary items)
+ {
+ this.items = items;
+ }
+
+ public bool contains<T>(IKey<T> key)
+ {
+ return key.is_found_in(items);
+ }
+
+ public void add<T>(IKey<T> key, T value)
+ {
+ key.add_value_to(items, value);
+ }
+
+ public T value_for<T>(IKey<T> key)
+ {
+ return key.parse_from(items);
+ }
+
+ public void remove<T>(IKey<T> key)
+ {
+ key.remove_from(items);
+ }
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/ContextFactory.cs
@@ -0,0 +1,15 @@
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public interface IContextFactory
+ {
+ IContext create_for(IScopedStorage storage);
+ }
+
+ public class ContextFactory : IContextFactory
+ {
+ public IContext create_for(IScopedStorage storage)
+ {
+ return new Context(storage.provide_storage());
+ }
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/ContextFactorySpecs.cs
@@ -0,0 +1,31 @@
+using System.Collections;
+using developwithpassion.bdd.contexts;
+using Gorilla.Commons.Testing;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public class ContextFactorySpecs
+ {
+ }
+
+ [Concern(typeof (ContextFactory))]
+ public class when_creating_a_new_context : concerns_for<IContextFactory, ContextFactory>
+ {
+ context c = () =>
+ {
+ scope = an<IScopedStorage>();
+ storage = an<IDictionary>();
+
+ when_the(scope).is_told_to(x => x.provide_storage()).it_will_return(storage);
+ };
+
+ because b = () => { result = sut.create_for(scope); };
+
+ it should_return_a_context_that_represents_the_specified_scope =
+ () => result.should_be_an_instance_of<Context>();
+
+ static IDictionary storage;
+ static IScopedStorage scope;
+ static IContext result;
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/CurrentThread.cs
@@ -0,0 +1,19 @@
+using System.Threading;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public class CurrentThread : IThread
+ {
+ public T provide_slot_for<T>() where T : class, new()
+ {
+ var slot = Thread.GetNamedDataSlot(create_key_for<T>());
+ if (null == Thread.GetData(slot)) Thread.SetData(slot, new T());
+ return (T) Thread.GetData(slot);
+ }
+
+ string create_key_for<T>()
+ {
+ return Thread.CurrentThread.ManagedThreadId + GetType().FullName + typeof (T).FullName;
+ }
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/IChangeTracker.cs
@@ -0,0 +1,17 @@
+using System;
+using Gorilla.Commons.Utility.Core;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public interface IChangeTracker : IDisposable
+ {
+ bool is_dirty();
+ void commit_to(IDatabase database);
+ }
+
+ public interface IChangeTracker<T> : IChangeTracker where T : IIdentifiable<Guid>
+ {
+ void register(T value);
+ void delete(T entity);
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/IChangeTrackerFactory.cs
@@ -0,0 +1,10 @@
+using System;
+using Gorilla.Commons.Utility.Core;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public interface IChangeTrackerFactory
+ {
+ IChangeTracker<T> create_for<T>() where T : IIdentifiable<Guid>;
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/IContext.cs
@@ -0,0 +1,10 @@
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public interface IContext
+ {
+ bool contains<T>(IKey<T> key);
+ void add<T>(IKey<T> key, T value);
+ T value_for<T>(IKey<T> key);
+ void remove<T>(IKey<T> key);
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/IDatabase.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using Gorilla.Commons.Utility.Core;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public interface IDatabase
+ {
+ IEnumerable<T> fetch_all<T>() where T : IIdentifiable<Guid>;
+ void apply(IStatement statement);
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/IDatabaseConnection.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public interface IDatabaseConnection : IDisposable
+ {
+ IEnumerable<T> query<T>();
+ IEnumerable<T> query<T>(Predicate<T> predicate);
+ void delete<T>(T entity);
+ void commit();
+ void store<T>(T entity);
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/IdentityMapProxy.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using Gorilla.Commons.Utility.Core;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public class IdentityMapProxy<Key, Value> : IIdentityMap<Key, Value> where Value : IIdentifiable<Guid>
+ {
+ readonly IIdentityMap<Key, Value> real_map;
+ readonly IChangeTracker<Value> change_tracker;
+
+ public IdentityMapProxy(IChangeTracker<Value> change_tracker, IIdentityMap<Key, Value> real_map)
+ {
+ this.change_tracker = change_tracker;
+ this.real_map = real_map;
+ }
+
+ public IEnumerable<Value> all()
+ {
+ return real_map.all();
+ }
+
+ public void add(Key key, Value value)
+ {
+ change_tracker.register(value);
+ real_map.add(key, value);
+ }
+
+ public void update_the_item_for(Key key, Value new_value)
+ {
+ real_map.update_the_item_for(key, new_value);
+ }
+
+ public bool contains_an_item_for(Key key)
+ {
+ return real_map.contains_an_item_for(key);
+ }
+
+ public Value item_that_belongs_to(Key key)
+ {
+ return real_map.item_that_belongs_to(key);
+ }
+
+ public void evict(Key key)
+ {
+ change_tracker.delete(real_map.item_that_belongs_to(key));
+ real_map.evict(key);
+ }
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/IdentityMapSpecs.cs
@@ -0,0 +1,95 @@
+using developwithpassion.bdd.contexts;
+using Gorilla.Commons.Testing;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ [Concern(typeof (IdentityMap<,>))]
+ public class behaves_like_identity_map : concerns_for<IIdentityMap<int, string>, IdentityMap<int, string>>
+ {
+ public override IIdentityMap<int, string> create_sut()
+ {
+ return new IdentityMap<int, string>();
+ }
+ }
+
+ [Concern(typeof (IdentityMap<,>))]
+ public class when_getting_an_item_from_the_identity_map_for_an_item_that_has_been_added : behaves_like_identity_map
+ {
+ it should_return_the_item_that_was_added_for_the_given_key = () => result.should_be_equal_to("1");
+
+ because b = () =>
+ {
+ sut.add(1, "1");
+ result = sut.item_that_belongs_to(1);
+ };
+
+ static string result;
+ }
+
+ [Concern(typeof (IdentityMap<,>))]
+ public class when_getting_an_item_from_the_identity_map_that_has_not_been_added : behaves_like_identity_map
+ {
+ it should_return_the_default_value_for_that_type = () => result.should_be_equal_to(null);
+
+ because b = () => { result = sut.item_that_belongs_to(2); };
+
+ static string result;
+ }
+
+ [Concern(typeof (IdentityMap<,>))]
+ public class when_checking_if_an_item_has_been_added_to_the_identity_map_that_has_been_added :
+ behaves_like_identity_map
+ {
+ it should_return_true = () => result.should_be_true();
+
+ because b = () =>
+ {
+ sut.add(10, "10");
+ result = sut.contains_an_item_for(10);
+ };
+
+ static bool result;
+ }
+
+ [Concern(typeof (IdentityMap<,>))]
+ public class when_checking_if_an_item_has_been_added_to_the_identity_map_that_has_not_been_added :
+ behaves_like_identity_map
+ {
+ it should_return_false = () => result.should_be_false();
+
+ because b = () => { result = sut.contains_an_item_for(9); };
+
+ static bool result;
+ }
+
+ [Concern(typeof (IdentityMap<,>))]
+ public class when_updating_the_value_for_a_key_that_has_already_been_added_to_the_identity_map :
+ behaves_like_identity_map
+ {
+ it should_replace_the_old_item_with_the_new_one = () => result.should_be_equal_to("7");
+
+ because b = () =>
+ {
+ sut.add(6, "6");
+ sut.update_the_item_for(6, "7");
+ result = sut.item_that_belongs_to(6);
+ };
+
+ static string result;
+ }
+
+ [Concern(typeof (IdentityMap<,>))]
+ public class when_updating_the_value_for_a_key_that_has_not_been_added_to_the_identity_map :
+ behaves_like_identity_map
+ {
+ it should_add_the_new_item = () => result.should_be_equal_to("3");
+
+ because b = () =>
+ {
+ sut.update_the_item_for(3, "3");
+ result = sut.item_that_belongs_to(3);
+ };
+
+ static string result;
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/IIdentityMap.cs
@@ -0,0 +1,59 @@
+using System.Collections.Generic;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public interface IIdentityMap<TKey, TValue>
+ {
+ IEnumerable<TValue> all();
+ void add(TKey key, TValue value);
+ void update_the_item_for(TKey key, TValue new_value);
+ bool contains_an_item_for(TKey key);
+ TValue item_that_belongs_to(TKey key);
+ void evict(TKey key);
+ }
+
+ public class IdentityMap<TKey, TValue> : IIdentityMap<TKey, TValue>
+ {
+ readonly IDictionary<TKey, TValue> items_in_map;
+
+ public IdentityMap() : this(new Dictionary<TKey, TValue>())
+ {
+ }
+
+ public IdentityMap(IDictionary<TKey, TValue> items_in_map)
+ {
+ this.items_in_map = items_in_map;
+ }
+
+ public IEnumerable<TValue> all()
+ {
+ return items_in_map.Values;
+ }
+
+ public void add(TKey key, TValue value)
+ {
+ items_in_map.Add(key, value);
+ }
+
+ public void update_the_item_for(TKey key, TValue new_value)
+ {
+ if (contains_an_item_for(key)) items_in_map[key] = new_value;
+ else add(key, new_value);
+ }
+
+ public bool contains_an_item_for(TKey key)
+ {
+ return items_in_map.ContainsKey(key);
+ }
+
+ public TValue item_that_belongs_to(TKey key)
+ {
+ return contains_an_item_for(key) ? items_in_map[key] : default(TValue);
+ }
+
+ public void evict(TKey key)
+ {
+ if (contains_an_item_for(key)) items_in_map.Remove(key);
+ }
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/IKey.cs
@@ -0,0 +1,12 @@
+using System.Collections;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public interface IKey<T>
+ {
+ bool is_found_in(IDictionary items);
+ T parse_from(IDictionary items);
+ void remove_from(IDictionary items);
+ void add_value_to(IDictionary items, T value);
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/IScopedStorage.cs
@@ -0,0 +1,9 @@
+using System.Collections;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public interface IScopedStorage
+ {
+ IDictionary provide_storage();
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/IStatement.cs
@@ -0,0 +1,7 @@
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public interface IStatement
+ {
+ void prepare(IDatabaseConnection connection);
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/IStatementRegistry.cs
@@ -0,0 +1,11 @@
+using System;
+using Gorilla.Commons.Utility.Core;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public interface IStatementRegistry
+ {
+ IStatement prepare_delete_statement_for<T>(T entity) where T : IIdentifiable<Guid>;
+ IStatement prepare_command_for<T>(T entity) where T : IIdentifiable<Guid>;
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/IThread.cs
@@ -0,0 +1,7 @@
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public interface IThread
+ {
+ T provide_slot_for<T>() where T : class, new();
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/PerThread.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public class PerThread : IContext
+ {
+ readonly IDictionary<int, LocalDataStoreSlot> slots;
+ readonly object mutex = new object();
+
+ public PerThread()
+ {
+ slots = new Dictionary<int, LocalDataStoreSlot>();
+ }
+
+ public bool contains<T>(IKey<T> key)
+ {
+ return key.is_found_in(get_items());
+ }
+
+ public void add<T>(IKey<T> key, T value)
+ {
+ key.add_value_to(get_items(), value);
+ }
+
+ public T value_for<T>(IKey<T> key)
+ {
+ return key.parse_from(get_items());
+ }
+
+ public void remove<T>(IKey<T> key)
+ {
+ key.remove_from(get_items());
+ }
+
+ IDictionary get_items()
+ {
+ var id = Thread.CurrentThread.ManagedThreadId;
+ within_lock(() =>
+ {
+ if (!slots.ContainsKey(id))
+ {
+ var slot = Thread.GetNamedDataSlot(GetType().FullName);
+ slots.Add(id, slot);
+ Thread.SetData(slot, new Hashtable());
+ }
+ });
+ return (IDictionary) Thread.GetData(slots[id]);
+ }
+
+ void within_lock(Action action)
+ {
+ lock (mutex) action();
+ }
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/PerThreadScopedStorage.cs
@@ -0,0 +1,19 @@
+using System.Collections;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public class PerThreadScopedStorage : IScopedStorage
+ {
+ readonly IThread current_thread;
+
+ public PerThreadScopedStorage(IThread current_thread)
+ {
+ this.current_thread = current_thread;
+ }
+
+ public IDictionary provide_storage()
+ {
+ return current_thread.provide_slot_for<Hashtable>();
+ }
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/PerThreadScopedStorageSpecs.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections;
+using developwithpassion.bdd.contexts;
+using Gorilla.Commons.Testing;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public class PerThreadScopedStorageSpecs
+ {
+ }
+
+ [Concern(typeof (PerThreadScopedStorage))]
+ public class when_retrieving_the_storage_for_a_specific_thread :
+ concerns_for<IScopedStorage, PerThreadScopedStorage>
+ {
+ context c = () =>
+ {
+ thread_id = DateTime.Now.Ticks;
+ thread = the_dependency<IThread>();
+ storage = new Hashtable();
+ when_the(thread)
+ .is_told_to(x => x.provide_slot_for<Hashtable>())
+ .it_will_return(storage);
+ };
+
+ because b = () => { result = sut.provide_storage(); };
+
+ it should_return_the_storage_the_corresponds_to_the_current_thread = () => result.should_be_equal_to(storage);
+
+ static IDictionary result;
+ static IThread thread;
+ static long thread_id;
+ static Hashtable storage;
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/Session.cs
@@ -0,0 +1,104 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Gorilla.Commons.Infrastructure.Logging;
+using Gorilla.Commons.Utility.Core;
+using Gorilla.Commons.Utility.Extensions;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public interface ISession : IDisposable
+ {
+ T find<T>(Guid guid) where T : IIdentifiable<Guid>;
+ IEnumerable<T> all<T>() where T : IIdentifiable<Guid>;
+ void save<T>(T entity) where T : IIdentifiable<Guid>;
+ void delete<T>(T entity) where T : IIdentifiable<Guid>;
+ void flush();
+ bool is_dirty();
+ }
+
+ public class Session : ISession
+ {
+ ITransaction transaction;
+ readonly IDatabase database;
+ readonly IDictionary<Type, object> identity_maps;
+ long id;
+
+ public Session(ITransaction transaction, IDatabase database)
+ {
+ this.database = database;
+ this.transaction = transaction;
+ identity_maps = new Dictionary<Type, object>();
+ id = DateTime.Now.Ticks;
+ }
+
+ public T find<T>(Guid id) where T : IIdentifiable<Guid>
+ {
+ if (get_identity_map_for<T>().contains_an_item_for(id))
+ {
+ return get_identity_map_for<T>().item_that_belongs_to(id);
+ }
+
+ var entity = database.fetch_all<T>().Single(x => x.id.Equals(id));
+ get_identity_map_for<T>().add(id, entity);
+ return entity;
+ }
+
+ public IEnumerable<T> all<T>() where T : IIdentifiable<Guid>
+ {
+ database
+ .fetch_all<T>()
+ .where(x => !get_identity_map_for<T>().contains_an_item_for(x.id))
+ .each(x => get_identity_map_for<T>().add(x.id, x));
+ return get_identity_map_for<T>().all();
+ }
+
+ public void save<T>(T entity) where T : IIdentifiable<Guid>
+ {
+ this.log().debug("saving {0}: {1}", id, entity);
+ get_identity_map_for<T>().add(entity.id, entity);
+ }
+
+ public void delete<T>(T entity) where T : IIdentifiable<Guid>
+ {
+ get_identity_map_for<T>().evict(entity.id);
+ }
+
+ public void flush()
+ {
+ this.log().debug("flushing session {0}", id);
+ transaction.commit_changes();
+ transaction = null;
+ }
+
+ public bool is_dirty()
+ {
+ this.log().debug("is dirty? {0}", id);
+ return null != transaction && transaction.is_dirty();
+ }
+
+ public void Dispose()
+ {
+ if (null != transaction) transaction.rollback_changes();
+ }
+
+ IIdentityMap<Guid, T> get_identity_map_for<T>() where T : IIdentifiable<Guid>
+ {
+ return identity_maps.ContainsKey(typeof (T))
+ ? identity_maps[typeof (T)].downcast_to<IIdentityMap<Guid, T>>()
+ : create_map_for<T>();
+ }
+
+ IIdentityMap<Guid, T> create_map_for<T>() where T : IIdentifiable<Guid>
+ {
+ var identity_map = transaction.create_for<T>();
+ identity_maps.Add(typeof (T), identity_map);
+ return identity_map;
+ }
+
+ public override string ToString()
+ {
+ return "session: {0}".formatted_using(id);
+ }
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/SessionFactory.cs
@@ -0,0 +1,25 @@
+using Gorilla.Commons.Utility.Core;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public interface ISessionFactory : IFactory<ISession>
+ {
+ }
+
+ public class SessionFactory : ISessionFactory
+ {
+ readonly IDatabase database;
+ readonly IChangeTrackerFactory factory;
+
+ public SessionFactory(IDatabase database, IChangeTrackerFactory factory)
+ {
+ this.database = database;
+ this.factory = factory;
+ }
+
+ public ISession create()
+ {
+ return new Session(new Transaction(database, factory), database);
+ }
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/SessionFactorySpecs.cs
@@ -0,0 +1,19 @@
+using developwithpassion.bdd.contexts;
+using Gorilla.Commons.Testing;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public class SessionFactorySpecs
+ {
+ }
+
+ [Concern(typeof (SessionFactory))]
+ public class when_creating_a_new_session : concerns_for<ISessionFactory, SessionFactory>
+ {
+ it should_return_a_new_session = () => result.should_not_be_null();
+
+ because b = () => { result = sut.create(); };
+
+ static ISession result;
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/SessionNotStartedException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public class SessionNotStartedException : Exception
+ {
+ public SessionNotStartedException() : base("A session could not be found. Did you forget to open a session?")
+ {
+ }
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/SessionProvider.cs
@@ -0,0 +1,25 @@
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public interface ISessionProvider
+ {
+ ISession get_the_current_session();
+ }
+
+ public class SessionProvider : ISessionProvider
+ {
+ readonly IContext context;
+ readonly IKey<ISession> session_key;
+
+ public SessionProvider(IContext context, IKey<ISession> session_key)
+ {
+ this.context = context;
+ this.session_key = session_key;
+ }
+
+ public ISession get_the_current_session()
+ {
+ if (!context.contains(session_key)) throw new SessionNotStartedException();
+ return context.value_for(session_key);
+ }
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/SessionSpecs.cs
@@ -0,0 +1,178 @@
+using System;
+using System.Collections.Generic;
+using developwithpassion.bdd.contexts;
+using Gorilla.Commons.Testing;
+using Gorilla.Commons.Utility.Core;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public class SessionSpecs
+ {
+ }
+
+ public class behaves_like_session : concerns_for<ISession, Session>
+ {
+ context c = () =>
+ {
+ transaction = the_dependency<ITransaction>();
+ database = the_dependency<IDatabase>();
+ };
+
+ static protected ITransaction transaction;
+ static protected IDatabase database;
+ }
+
+ [Concern(typeof (Session))]
+ public class when_saving_a_transient_item_to_a_session : behaves_like_session
+ {
+ it should_add_the_entity_to_the_identity_map = () => map.was_told_to(x => x.add(guid, entity));
+
+ context c = () =>
+ {
+ guid = Guid.NewGuid();
+ entity = an<ITestEntity>();
+ map = an<IIdentityMap<Guid, ITestEntity>>();
+
+ when_the(entity).is_told_to(x => x.id).it_will_return(guid);
+ when_the(transaction).is_told_to(x => x.create_for<ITestEntity>()).it_will_return(map);
+ };
+
+ because b = () => sut.save(entity);
+
+ static ITestEntity entity;
+ static IIdentityMap<Guid, ITestEntity> map;
+ static Id<Guid> guid;
+ }
+
+ [Concern(typeof (Session))]
+ public class when_commiting_the_changes_made_in_a_session : behaves_like_session
+ {
+ it should_commit_all_the_changes_from_the_running_transaction =
+ () => transaction.was_told_to(x => x.commit_changes());
+
+ it should_not_rollback_any_changes_from_the_running_transaction =
+ () => transaction.was_not_told_to(x => x.rollback_changes());
+
+ because b = () =>
+ {
+ sut.flush();
+ sut.Dispose();
+ };
+ }
+
+ [Concern(typeof (Session))]
+ public class when_closing_a_session_before_flushing_the_changes : behaves_like_session
+ {
+ it should_rollback_any_changes_made_in_the_current_transaction =
+ () => transaction.was_told_to(x => x.rollback_changes());
+
+ because b = () => sut.Dispose();
+ }
+
+ [Concern(typeof (Session))]
+ public class when_loading_all_instances_of_a_certain_type_and_some_have_already_been_loaded : behaves_like_session
+ {
+ it should_return_the_items_from_the_cache = () => results.should_contain(cached_item);
+
+ it should_exclude_duplicates_from_the_database = () => results.should_not_contain(database_item);
+
+ it should_add_items_from_the_database_to_the_identity_map =
+ () => identity_map.was_told_to(x => x.add(id_of_the_uncached_item, uncached_item));
+
+ context c = () =>
+ {
+ id = Guid.NewGuid();
+ id_of_the_uncached_item = Guid.NewGuid();
+ identity_map = an<IIdentityMap<Guid, ITestEntity>>();
+ cached_item = an<ITestEntity>();
+ database_item = an<ITestEntity>();
+ uncached_item = an<ITestEntity>();
+
+ when_the(cached_item).is_told_to(x => x.id).it_will_return(id);
+ when_the(database_item).is_told_to(x => x.id).it_will_return(id);
+ when_the(uncached_item).is_told_to(x => x.id).it_will_return(id_of_the_uncached_item);
+ when_the(transaction).is_told_to(x => x.create_for<ITestEntity>()).it_will_return( identity_map);
+ when_the(identity_map).is_told_to(x => x.contains_an_item_for(id)).it_will_return(true);
+ when_the(identity_map).is_told_to(x => x.all()).it_will_return(cached_item);
+ when_the(database).is_told_to(x => x.fetch_all<ITestEntity>())
+ .it_will_return(database_item, uncached_item);
+ };
+
+ because b = () =>
+ {
+ sut.find<ITestEntity>(id);
+ results = sut.all<ITestEntity>();
+ };
+
+ static IEnumerable<ITestEntity> results;
+ static Id<Guid> id;
+ static Id<Guid> id_of_the_uncached_item;
+ static ITestEntity cached_item;
+ static ITestEntity database_item;
+ static IIdentityMap<Guid, ITestEntity> identity_map;
+ static ITestEntity uncached_item;
+ }
+
+ [Concern(typeof (Session))]
+ public class when_looking_up_a_specific_entity_by_its_id_and_it_has_not_been_loaded_into_the_cache :
+ behaves_like_session
+ {
+ it should_return_that_item = () => { result.should_be_equal_to(correct_item); };
+
+ it should_add_that_item_to_the_identity_map = () => map.was_told_to(x => x.add(id, correct_item));
+
+ context c = () =>
+ {
+ id = Guid.NewGuid();
+ wrong_item = an<ITestEntity>();
+ correct_item = an<ITestEntity>();
+ map = an<IIdentityMap<Guid, ITestEntity>>();
+ when_the(wrong_item).is_told_to(x => x.id).it_will_return<Id<Guid>>(Guid.NewGuid());
+ when_the(correct_item).is_told_to(x => x.id).it_will_return(id);
+ when_the(database)
+ .is_told_to(x => x.fetch_all<ITestEntity>())
+ .it_will_return(wrong_item, correct_item);
+ when_the(transaction).is_told_to(x => x.create_for<ITestEntity>())
+ .it_will_return(map);
+ };
+
+ because b = () => { result = sut.find<ITestEntity>(id); };
+
+ static Id<Guid> id;
+ static IIdentifiable<Guid> result;
+ static ITestEntity correct_item;
+ static ITestEntity wrong_item;
+ static IIdentityMap<Guid, ITestEntity> map;
+ }
+
+ [Concern(typeof (Session))]
+ public class when_deleting_an_item_from_the_database : behaves_like_session
+ {
+ it should_remove_that_item_from_the_cache = () => map.was_told_to(x => x.evict(id));
+
+ context c = () =>
+ {
+ id = Guid.NewGuid();
+ entity = an<ITestEntity>();
+ map = an<IIdentityMap<Guid, ITestEntity>>();
+
+ when_the(entity).is_told_to(x => x.id).it_will_return(id);
+ when_the(transaction).is_told_to(x => x.create_for<ITestEntity>()).it_will_return(map);
+ when_the(database).is_told_to(x => x.fetch_all<ITestEntity>()).it_will_return(entity);
+ };
+
+ because b = () =>
+ {
+ sut.find<ITestEntity>(id);
+ sut.delete(entity);
+ };
+
+ static Id<Guid> id;
+ static IIdentityMap<Guid, ITestEntity> map;
+ static ITestEntity entity;
+ }
+
+ public interface ITestEntity : IIdentifiable<Guid>
+ {
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/SingletonScopedStorage.cs
@@ -0,0 +1,14 @@
+using System.Collections;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public class SingletonScopedStorage : IScopedStorage
+ {
+ static readonly IDictionary storage = new Hashtable();
+
+ public IDictionary provide_storage()
+ {
+ return storage;
+ }
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/StatementRegistry.cs
@@ -0,0 +1,48 @@
+using System;
+using Gorilla.Commons.Utility.Core;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public class StatementRegistry : IStatementRegistry
+ {
+ public IStatement prepare_delete_statement_for<T>(T entity) where T : IIdentifiable<Guid>
+ {
+ return new DeletionStatement<T>(entity);
+ }
+
+ public IStatement prepare_command_for<T>(T entity) where T : IIdentifiable<Guid>
+ {
+ return new SaveOrUpdateStatement<T>(entity);
+ }
+ }
+
+ public class SaveOrUpdateStatement<T> : IStatement where T : IIdentifiable<Guid>
+ {
+ readonly T entity;
+
+ public SaveOrUpdateStatement(T entity)
+ {
+ this.entity = entity;
+ }
+
+ public void prepare(IDatabaseConnection connection)
+ {
+ connection.store(entity);
+ }
+ }
+
+ public class DeletionStatement<T> : IStatement
+ {
+ readonly T entity;
+
+ public DeletionStatement(T entity)
+ {
+ this.entity = entity;
+ }
+
+ public void prepare(IDatabaseConnection connection)
+ {
+ connection.delete(entity);
+ }
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/TrackerEntry.cs
@@ -0,0 +1,47 @@
+using System.Reflection;
+using Gorilla.Commons.Infrastructure.Logging;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public interface ITrackerEntry<T>
+ {
+ T current { get; }
+ bool has_changes();
+ }
+
+ public class TrackerEntry<T> : ITrackerEntry<T>
+ {
+ readonly T original;
+
+ public TrackerEntry(T original, T current)
+ {
+ this.original = original;
+ this.current = current;
+ }
+
+ public T current { get; set; }
+
+ public bool has_changes()
+ {
+ this.log().debug("checking for changes");
+ var type = original.GetType();
+ foreach (var field in type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
+ {
+ var original_value = field.GetValue(original);
+ var current_value = field.GetValue(current);
+ if (original_value == null && current_value != null)
+ {
+ this.log().debug("{0} has changes: {1}", field, original);
+ return true;
+ }
+ if (original_value != null && !original_value.Equals(current_value))
+ {
+ this.log().debug("{0} has changes: {1}", field, original);
+ return true;
+ }
+ }
+ this.log().debug("has no changes: {0}", original);
+ return false;
+ }
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/TrackerEntryMapper.cs
@@ -0,0 +1,29 @@
+using Gorilla.Commons.Infrastructure.Cloning;
+using Gorilla.Commons.Utility.Core;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public interface ITrackerEntryMapper<T> : IMapper<T, ITrackerEntry<T>>
+ {
+ }
+
+ public class TrackerEntryMapper<T> : ITrackerEntryMapper<T>
+ {
+ readonly IPrototype prototype;
+
+ public TrackerEntryMapper(IPrototype prototype)
+ {
+ this.prototype = prototype;
+ }
+
+ public ITrackerEntry<T> map_from(T item)
+ {
+ return new TrackerEntry<T>(create_prototype(item), item);
+ }
+
+ T create_prototype(T item)
+ {
+ return prototype.clone(item);
+ }
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/TrackerEntrySpecs.cs
@@ -0,0 +1,140 @@
+using System;
+using developwithpassion.bdd.contexts;
+using Gorilla.Commons.Testing;
+using Gorilla.Commons.Utility.Core;
+using Gorilla.Commons.Utility.Extensions;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public class TrackerEntrySpecs
+ {
+ }
+
+ public abstract class behaves_like_tracker_entry : concerns_for<ITrackerEntry<Pillow>>
+ {
+ }
+
+ [Concern(typeof (ITrackerEntry<>))]
+ public class when_comparing_the_current_instance_of_a_component_with_its_original_and_it_has_changes :
+ behaves_like_tracker_entry
+ {
+ it should_indicate_that_there_are_changes = () => result.should_be_true();
+
+ because b = () => { result = sut.has_changes(); };
+
+ public override ITrackerEntry<Pillow> create_sut()
+ {
+ return new TrackerEntry<Pillow>(new Pillow("pink"), new Pillow("yellow"));
+ }
+
+ static bool result;
+ }
+
+ [Concern(typeof (ITrackerEntry<>))]
+ public class when_the_original_instance_has_a_null_field_that_is_now_not_null :
+ behaves_like_tracker_entry
+ {
+ it should_indicate_that_there_are_changes = () => result.should_be_true();
+
+ because b = () => { result = sut.has_changes(); };
+
+ public override ITrackerEntry<Pillow> create_sut()
+ {
+ return new TrackerEntry<Pillow>(new Pillow(null), new Pillow("yellow"));
+ }
+
+ static bool result;
+ }
+
+ [Concern(typeof (ITrackerEntry<>))]
+ public class when_the_original_instance_had_a_non_null_field_and_the_current_instance_has_a_null_field :
+ behaves_like_tracker_entry
+ {
+ it should_indicate_that_there_are_changes = () => result.should_be_true();
+
+ because b = () => { result = sut.has_changes(); };
+
+ context c = () =>
+ {
+ var id = Guid.NewGuid();
+ original = new Pillow("green", id);
+ current = new Pillow(null, id);
+ };
+
+ public override ITrackerEntry<Pillow> create_sut()
+ {
+ return new TrackerEntry<Pillow>(original, current);
+ }
+
+ static bool result;
+ static Pillow original;
+ static Pillow current;
+ }
+
+ [Concern(typeof (ITrackerEntry<>))]
+ public class when_the_original_instance_has_the_same_value_as_the_current_instance :
+ behaves_like_tracker_entry
+ {
+ it should_indicate_that_there_are_no_changes = () => result.should_be_false();
+
+ because b = () => { result = sut.has_changes(); };
+
+ context c = () =>
+ {
+ var id = Guid.NewGuid();
+ original = new Pillow("green", id);
+ current = new Pillow("green", id);
+ };
+
+ public override ITrackerEntry<Pillow> create_sut()
+ {
+ return new TrackerEntry<Pillow>(original, current);
+ }
+
+ static bool result;
+ static Pillow original;
+ static Pillow current;
+ }
+
+ public class Pillow : IIdentifiable<Guid>
+ {
+ readonly string color;
+
+ public Pillow(string color) : this(color, Guid.NewGuid())
+ {
+ }
+
+ public Pillow(string color, Guid id)
+ {
+ this.color = color;
+ this.id = id;
+ }
+
+ public Id<Guid> id { get; set; }
+
+ public bool Equals(Pillow other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return other.id.Equals(id);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != typeof (Pillow)) return false;
+ return Equals((Pillow) obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return id.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return "{0} id: {1}".formatted_using(base.ToString(), id);
+ }
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/Transaction.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Gorilla.Commons.Utility.Core;
+using Gorilla.Commons.Utility.Extensions;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public interface ITransaction
+ {
+ IIdentityMap<Guid, T> create_for<T>() where T : IIdentifiable<Guid>;
+ void commit_changes();
+ void rollback_changes();
+ bool is_dirty();
+ }
+
+ public class Transaction : ITransaction
+ {
+ readonly IDatabase database;
+ readonly IChangeTrackerFactory factory;
+ readonly IDictionary<Type, IChangeTracker> change_trackers;
+
+ public Transaction(IDatabase database, IChangeTrackerFactory factory)
+ {
+ this.factory = factory;
+ this.database = database;
+ change_trackers = new Dictionary<Type, IChangeTracker>();
+ }
+
+ public IIdentityMap<Guid, T> create_for<T>() where T : IIdentifiable<Guid>
+ {
+ return new IdentityMapProxy<Guid, T>(get_change_tracker_for<T>(), new IdentityMap<Guid, T>());
+ }
+
+ public void commit_changes()
+ {
+ change_trackers.Values.where(x => x.is_dirty()).each(x => x.commit_to(database));
+ }
+
+ public void rollback_changes()
+ {
+ change_trackers.each(x => x.Value.Dispose());
+ change_trackers.Clear();
+ }
+
+ public bool is_dirty()
+ {
+ return change_trackers.Values.Count(x => x.is_dirty()) > 0;
+ }
+
+ IChangeTracker<T> get_change_tracker_for<T>() where T : IIdentifiable<Guid>
+ {
+ if (!change_trackers.ContainsKey(typeof (T))) change_trackers.Add(typeof (T), factory.create_for<T>());
+ return change_trackers[typeof (T)].downcast_to<IChangeTracker<T>>();
+ }
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/TransactionSpecs.cs
@@ -0,0 +1,113 @@
+using System;
+using developwithpassion.bdd.contexts;
+using Gorilla.Commons.Testing;
+using Gorilla.Commons.Utility.Core;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public class TransactionSpecs
+ {
+ }
+
+ [Concern(typeof (Transaction))]
+ public class behaves_like_transaction : concerns_for<ITransaction, Transaction>
+ {
+ context c = () =>
+ {
+ database = the_dependency<IDatabase>();
+ factory = the_dependency<IChangeTrackerFactory>();
+ };
+
+ static protected IDatabase database;
+ static protected IChangeTrackerFactory factory;
+ }
+
+ [Concern(typeof (Transaction))]
+ public class when_creating_an_identity_map_for_a_specific_entity : behaves_like_transaction
+ {
+ it should_return_a_new_identity_map = () => result.should_not_be_null();
+
+ because b = () => { result = sut.create_for<IIdentifiable<Guid>>(); };
+
+ static IIdentityMap<Guid, IIdentifiable<Guid>> result;
+ }
+
+ [Concern(typeof (Transaction))]
+ public class when_committing_a_transaction_and_an_item_in_the_identity_map_has_changed : behaves_like_transaction
+ {
+ it should_commit_the_changes_to_that_item =
+ () => tracker.was_told_to<IChangeTracker<IMovie>>(x => x.commit_to(database));
+
+ context c = () =>
+ {
+ movie = new Movie("Goldeneye");
+ tracker = an<IChangeTracker<IMovie>>();
+
+ when_the(factory).is_told_to(x => x.create_for<IMovie>()).it_will_return(tracker);
+ when_the(tracker).is_told_to(x => x.is_dirty()).it_will_return(true);
+ };
+
+
+ because b = () =>
+ {
+ sut.create_for<IMovie>().add(movie.id, movie);
+ movie.change_name_to("Austin Powers");
+ sut.commit_changes();
+ };
+
+ static IMovie movie;
+ static IChangeTracker<IMovie> tracker;
+ }
+
+ [Concern(typeof (Transaction))]
+ public class when_deleting_a_set_of_entities_from_the_database : behaves_like_transaction
+ {
+ it should_prepare_to_delete_that_item_form_the_database = () => tracker.was_told_to(x => x.delete(movie));
+
+ it should_delete_all_items_marked_for_deletion = () => tracker.was_told_to(x => x.commit_to(database));
+
+ context c = () =>
+ {
+ movie = new Movie("Goldeneye");
+ tracker = an<IChangeTracker<IMovie>>();
+
+ when_the(factory).is_told_to(x => x.create_for<IMovie>()).it_will_return(tracker);
+ when_the(tracker).is_told_to(x => x.is_dirty()).it_will_return(true);
+ };
+
+ because b = () =>
+ {
+ var map = sut.create_for<IMovie>();
+ map.add(movie.id, movie);
+ map.evict(movie.id);
+ sut.commit_changes();
+ };
+
+ static IMovie movie;
+ static IChangeTracker<IMovie> tracker;
+ }
+
+ public interface IMovie : IIdentifiable<Guid>
+ {
+ string name { get; }
+ void change_name_to(string name);
+ }
+
+ internal class Movie : IMovie
+ {
+ public Movie(string name)
+ {
+ id = Guid.NewGuid();
+ this.name = name;
+ }
+
+ public string name { get; set; }
+
+ public void change_name_to(string new_name)
+ {
+ name = new_name;
+ }
+
+ public Id<Guid> id { get; set; }
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/Transactions/TypedKey.cs
@@ -0,0 +1,50 @@
+using System.Collections;
+
+namespace Gorilla.Commons.Infrastructure.Transactions
+{
+ public class TypedKey<T> : IKey<T>
+ {
+ public bool is_found_in(IDictionary items)
+ {
+ return items.Contains(create_key());
+ }
+
+ public T parse_from(IDictionary items)
+ {
+ return (T) items[create_key()];
+ }
+
+ public void remove_from(IDictionary items)
+ {
+ if (is_found_in(items)) items.Remove(create_key());
+ }
+
+ public void add_value_to(IDictionary items, T value)
+ {
+ items[create_key()] = value;
+ }
+
+ public bool Equals(TypedKey<T> obj)
+ {
+ return !ReferenceEquals(null, obj);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != typeof (TypedKey<T>)) return false;
+ return Equals((TypedKey<T>) obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return GetType().GetHashCode();
+ }
+
+ string create_key()
+ {
+ return GetType().FullName;
+ }
+ }
+}
\ No newline at end of file
product/MoMoney.DataAccess/MoMoney.DataAccess.csproj
@@ -93,6 +93,44 @@
<Compile Include="Db40\DatabaseConnection.cs" />
<Compile Include="IConnectionFactory.cs" />
<Compile Include="IDatabaseConfiguration.cs" />
+ <Compile Include="Transactions\ChangeTracker.cs" />
+ <Compile Include="Transactions\ChangeTrackerFactory.cs" />
+ <Compile Include="Transactions\ChangeTrackerFactorySpecs.cs" />
+ <Compile Include="Transactions\ChangeTrackerSpecs.cs" />
+ <Compile Include="Transactions\Context.cs" />
+ <Compile Include="Transactions\ContextFactory.cs" />
+ <Compile Include="Transactions\ContextFactorySpecs.cs" />
+ <Compile Include="Transactions\CurrentThread.cs" />
+ <Compile Include="Transactions\IChangeTracker.cs" />
+ <Compile Include="Transactions\IChangeTrackerFactory.cs" />
+ <Compile Include="Transactions\IContext.cs" />
+ <Compile Include="Transactions\IDatabase.cs" />
+ <Compile Include="Transactions\IDatabaseConnection.cs" />
+ <Compile Include="Transactions\IdentityMapProxy.cs" />
+ <Compile Include="Transactions\IdentityMapSpecs.cs" />
+ <Compile Include="Transactions\IIdentityMap.cs" />
+ <Compile Include="Transactions\IKey.cs" />
+ <Compile Include="Transactions\IScopedStorage.cs" />
+ <Compile Include="Transactions\IStatement.cs" />
+ <Compile Include="Transactions\IStatementRegistry.cs" />
+ <Compile Include="Transactions\IThread.cs" />
+ <Compile Include="Transactions\PerThread.cs" />
+ <Compile Include="Transactions\PerThreadScopedStorage.cs" />
+ <Compile Include="Transactions\PerThreadScopedStorageSpecs.cs" />
+ <Compile Include="Transactions\Session.cs" />
+ <Compile Include="Transactions\SessionFactory.cs" />
+ <Compile Include="Transactions\SessionFactorySpecs.cs" />
+ <Compile Include="Transactions\SessionNotStartedException.cs" />
+ <Compile Include="Transactions\SessionProvider.cs" />
+ <Compile Include="Transactions\SessionSpecs.cs" />
+ <Compile Include="Transactions\SingletonScopedStorage.cs" />
+ <Compile Include="Transactions\StatementRegistry.cs" />
+ <Compile Include="Transactions\TrackerEntry.cs" />
+ <Compile Include="Transactions\TrackerEntryMapper.cs" />
+ <Compile Include="Transactions\TrackerEntrySpecs.cs" />
+ <Compile Include="Transactions\Transaction.cs" />
+ <Compile Include="Transactions\TransactionSpecs.cs" />
+ <Compile Include="Transactions\TypedKey.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MoMoney.Domain\MoMoney.Domain.csproj">
product/MoMoney.Domain/Core/Entity.cs
@@ -16,7 +16,7 @@ namespace MoMoney.Domain.Core
id = Guid.NewGuid();
}
- public Guid id { get; private set; }
+ public Id<Guid> id { get; private set; }
public bool Equals(Entity<T> obj)
{
product/MoMoney.Presentation/Model/Projects/ProjectController.cs
@@ -1,11 +1,11 @@
using Gorilla.Commons.Infrastructure.Eventing;
using Gorilla.Commons.Infrastructure.FileSystem;
using Gorilla.Commons.Infrastructure.Logging;
-using Gorilla.Commons.Infrastructure.Transactions;
using Gorilla.Commons.Utility.Core;
using Gorilla.Commons.Utility.Extensions;
using MoMoney.Presentation.Model.messages;
using MoMoney.Service.Infrastructure;
+using MoMoney.Service.Infrastructure.Transactions;
namespace MoMoney.Presentation.Model.Projects
{
product/MoMoney.Presentation/Model/Projects/ProjectControllerSpecs.cs
@@ -2,11 +2,11 @@ using System;
using developwithpassion.bdd.contexts;
using Gorilla.Commons.Infrastructure.Eventing;
using Gorilla.Commons.Infrastructure.FileSystem;
-using Gorilla.Commons.Infrastructure.Transactions;
using Gorilla.Commons.Testing;
using Gorilla.Commons.Utility.Extensions;
using MoMoney.Presentation.Model.messages;
using MoMoney.Service.Infrastructure;
+using MoMoney.Service.Infrastructure.Transactions;
namespace MoMoney.Presentation.Model.Projects
{
product/MoMoney.Presentation/Presenters/Shell/NotificationIconPresenter.cs
@@ -1,6 +1,5 @@
using System.Net.NetworkInformation;
using Gorilla.Commons.Infrastructure.Eventing;
-using MoMoney.Modules.Core;
using MoMoney.Presentation.Model.messages;
using MoMoney.Presentation.Resources;
using MoMoney.Presentation.Views.Shell;
product/MoMoney.Presentation/Presenters/Shell/StatusBarPresenter.cs
@@ -1,7 +1,6 @@
using Gorilla.Commons.Infrastructure.Eventing;
using Gorilla.Commons.Utility;
using Gorilla.Commons.Utility.Extensions;
-using MoMoney.Modules.Core;
using MoMoney.Presentation.Model.messages;
using MoMoney.Presentation.Resources;
using MoMoney.Presentation.Views.Shell;
product/MoMoney.Presentation/Presenters/Shell/TaskTrayPresenter.cs
@@ -1,5 +1,4 @@
using Gorilla.Commons.Infrastructure.Eventing;
-using MoMoney.Modules.Core;
using MoMoney.Presentation.Model.messages;
using MoMoney.Presentation.Views.Shell;
product/MoMoney.Presentation/Presenters/Shell/TitleBarPresenter.cs
@@ -1,6 +1,5 @@
using Gorilla.Commons.Infrastructure.Eventing;
using Gorilla.Commons.Infrastructure.Logging;
-using MoMoney.Modules.Core;
using MoMoney.Presentation.Model.messages;
using MoMoney.Presentation.Model.Projects;
using MoMoney.Presentation.Views.Shell;
product/MoMoney.Presentation/Presenters/Shell/UnhandledErrorPresenter.cs
@@ -1,5 +1,4 @@
using Gorilla.Commons.Infrastructure.Eventing;
-using MoMoney.Modules.Core;
using MoMoney.Presentation.Core;
using MoMoney.Presentation.Model.messages;
using MoMoney.Presentation.Presenters.Commands;
product/MoMoney.Presentation/Views/AddCompanyView.cs
@@ -42,8 +42,8 @@ namespace MoMoney.Presentation.Views
{
ux_companys_listing.DataSource = companies.databind();
- listView1.Items.Clear();
- listView1.Items.AddRange(companies.Select(x => new ListViewItem(x.name, 0)).ToArray());
+ //listView1.Items.Clear();
+ //listView1.Items.AddRange(companies.Select(x => new ListViewItem(x.name, 0)).ToArray());
}
}
}
\ No newline at end of file
product/MoMoney.Presentation/IModule.cs
@@ -1,6 +1,6 @@
using Gorilla.Commons.Utility.Core;
-namespace MoMoney.Modules.Core
+namespace MoMoney.Presentation
{
public interface IModule : ICommand
{
product/MoMoney.Service/Application/Public/AddNewIncomeCommand.svc
@@ -1,1 +0,0 @@
-๏ปฟ<%@ ServiceHost Language="C#" Service="MoMoney.Service.Application.AddNewIncomeCommand" CodeBehind="MoMoney.Service.Application.AddNewIncomeCommand.cs" />
\ No newline at end of file
product/MoMoney.Service/Application/AddNewIncomeCommandSpecs.cs
@@ -2,6 +2,7 @@ using System;
using developwithpassion.bdd.contexts;
using Gorilla.Commons.Testing;
using Gorilla.Commons.Utility;
+using Gorilla.Commons.Utility.Core;
using MoMoney.Domain.Accounting;
using MoMoney.Domain.Core;
using MoMoney.Domain.repositories;
@@ -41,7 +42,7 @@ namespace MoMoney.Service.Application
var a_company = an<ICompany>();
var matching_income = an<IIncome>();
var today = new Date(2008, 12, 26);
- var id = Guid.NewGuid();
+ Id<Guid> id = Guid.NewGuid();
income = new IncomeSubmissionDto
{
product/MoMoney.Service/Infrastructure/Transactions/EmptyUnitOfWork.cs
@@ -0,0 +1,21 @@
+using Gorilla.Commons.Infrastructure.Logging;
+
+namespace MoMoney.Service.Infrastructure.Transactions
+{
+ public class EmptyUnitOfWork : IUnitOfWork
+ {
+ public void commit()
+ {
+ this.log().debug("committed empty unit of work");
+ }
+
+ public bool is_dirty()
+ {
+ return false;
+ }
+
+ public void Dispose()
+ {
+ }
+ }
+}
\ No newline at end of file
product/MoMoney.Service/Infrastructure/Transactions/UnitOfWork.cs
@@ -0,0 +1,41 @@
+using System;
+using Gorilla.Commons.Infrastructure.Transactions;
+
+namespace MoMoney.Service.Infrastructure.Transactions
+{
+ public interface IUnitOfWork : IDisposable
+ {
+ void commit();
+ bool is_dirty();
+ }
+
+ public class UnitOfWork : IUnitOfWork
+ {
+ readonly ISession session;
+ readonly IContext context;
+ readonly IKey<ISession> key;
+
+ public UnitOfWork(ISession session, IContext context, IKey<ISession> key)
+ {
+ this.session = session;
+ this.context = context;
+ this.key = key;
+ }
+
+ public void commit()
+ {
+ if (is_dirty()) session.flush();
+ }
+
+ public bool is_dirty()
+ {
+ return session.is_dirty();
+ }
+
+ public void Dispose()
+ {
+ context.remove(key);
+ session.Dispose();
+ }
+ }
+}
\ No newline at end of file
product/MoMoney.Service/Infrastructure/Transactions/UnitOfWorkFactory.cs
@@ -0,0 +1,40 @@
+using Gorilla.Commons.Infrastructure.Transactions;
+using Gorilla.Commons.Utility.Core;
+
+namespace MoMoney.Service.Infrastructure.Transactions
+{
+ public interface IUnitOfWorkFactory : IFactory<IUnitOfWork>
+ {
+ }
+
+ public class UnitOfWorkFactory : IUnitOfWorkFactory
+ {
+ readonly IContext context;
+ readonly ISessionFactory factory;
+ readonly IKey<ISession> key;
+
+ public UnitOfWorkFactory(IContext context, ISessionFactory factory, IKey<ISession> key)
+ {
+ this.context = context;
+ this.key = key;
+ this.factory = factory;
+ }
+
+ public IUnitOfWork create()
+ {
+ return unit_of_work_been_started() ? new EmptyUnitOfWork() : start_a_new_unit_of_work();
+ }
+
+ bool unit_of_work_been_started()
+ {
+ return context.contains(key);
+ }
+
+ IUnitOfWork start_a_new_unit_of_work()
+ {
+ var session = factory.create();
+ context.add(key, session);
+ return new UnitOfWork(session, context, key);
+ }
+ }
+}
\ No newline at end of file
product/MoMoney.Service/Infrastructure/Transactions/UnitOfWorkFactorySpecs.cs
@@ -0,0 +1,78 @@
+using developwithpassion.bdd.contexts;
+using Gorilla.Commons.Infrastructure.Transactions;
+using Gorilla.Commons.Testing;
+
+namespace MoMoney.Service.Infrastructure.Transactions
+{
+ public class UnitOfWorkFactorySpecs
+ {
+ }
+
+ [Concern(typeof (UnitOfWorkFactory))]
+ public abstract class concerns_for_unit_of_work_factory : concerns_for<IUnitOfWorkFactory, UnitOfWorkFactory>
+ {
+ context c = () =>
+ {
+ session_context = the_dependency<IContext>();
+ factory = the_dependency<ISessionFactory>();
+ key = the_dependency<IKey<ISession>>();
+ };
+
+ static protected IContext session_context;
+ static protected ISessionFactory factory;
+ static protected IKey<ISession> key;
+ }
+
+ [Concern(typeof (UnitOfWorkFactory))]
+ public class when_a_unit_of_work_has_not_been_started : concerns_for_unit_of_work_factory
+ {
+ context c = () => { when_the(session_context).is_told_to(x => x.contains(key)).it_will_return(false); };
+ }
+
+ [Concern(typeof (UnitOfWorkFactory))]
+ public class when_a_unit_of_work_has_been_started : concerns_for_unit_of_work_factory
+ {
+ context c = () => { when_the(session_context).is_told_to(x => x.contains(key)).it_will_return(true); };
+ }
+
+ [Concern(typeof (UnitOfWorkFactory))]
+ public class when_creating_a_new_unit_of_work : when_a_unit_of_work_has_not_been_started
+ {
+ context c = () =>
+ {
+ session = an<ISession>();
+ when_the(factory).is_told_to(x => x.create()).it_will_return(session);
+ };
+
+ because b = () => { result = sut.create(); };
+
+ it should_create_a_new_unit_of_work = () => factory.was_told_to(x => x.create());
+
+ it should_add_the_session_to_the_current_context = () => session_context.was_told_to(x => x.add(key, session));
+
+ it should_return_a_brand_new_unit_of_work = () =>
+ {
+ result.should_not_be_null();
+ result.should_be_an_instance_of<UnitOfWork>();
+ };
+
+ static IUnitOfWork result;
+ static ISession session;
+ }
+
+ [Concern(typeof (UnitOfWorkFactory))]
+ public class when_attempting_to_create_a_new_unit_of_work : when_a_unit_of_work_has_been_started
+ {
+ because b = () => { result = sut.create(); };
+
+ it should_not_create_a_new_unit_of_work = () => factory.was_not_told_to(x => x.create());
+
+ it should_return_an_empty_unit_of_work = () =>
+ {
+ result.should_not_be_null();
+ result.should_be_an_instance_of<EmptyUnitOfWork>();
+ };
+
+ static IUnitOfWork result;
+ }
+}
\ No newline at end of file
product/MoMoney.Service/Infrastructure/Transactions/UnitOfWorkSpecs.cs
@@ -0,0 +1,67 @@
+using developwithpassion.bdd.contexts;
+using Gorilla.Commons.Infrastructure.Transactions;
+using Gorilla.Commons.Testing;
+
+namespace MoMoney.Service.Infrastructure.Transactions
+{
+ public class UnitOfWorkSpecs
+ {
+ }
+
+ [Concern(typeof (UnitOfWork))]
+ public abstract class behaves_like_unit_of_work : concerns_for<IUnitOfWork, UnitOfWork>
+ {
+ context c = () =>
+ {
+ session_context = the_dependency<IContext>();
+ session = the_dependency<ISession>();
+ key = the_dependency<IKey<ISession>>();
+ };
+
+ static protected IContext session_context;
+ static protected ISession session;
+ static protected IKey<ISession> key;
+ }
+
+ [Concern(typeof (UnitOfWork))]
+ public abstract class when_a_unit_of_work_has_unsaved_changes : behaves_like_unit_of_work
+ {
+ context c = () => when_the(session).is_told_to(x => x.is_dirty()).it_will_return(true);
+ }
+
+ [Concern(typeof (UnitOfWork))]
+ public abstract class when_a_unit_of_work_has_no_changes : behaves_like_unit_of_work
+ {
+ context c = () => when_the(session).is_told_to(x => x.is_dirty()).it_will_return(false);
+ }
+
+ [Concern(typeof (UnitOfWork))]
+ public class when_checking_if_a_unit_of_work_has_any_unsaved_changes : when_a_unit_of_work_has_unsaved_changes
+ {
+ it should_return_true = () => result.should_be_true();
+ because b = () => { result = sut.is_dirty(); };
+ static bool result;
+ }
+
+ [Concern(typeof (UnitOfWork))]
+ public class when_commiting_a_unit_of_work : when_a_unit_of_work_has_unsaved_changes
+ {
+ it should_flush_the_current_session = () => session.was_told_to(x => x.flush());
+ because b = () => sut.commit();
+ }
+
+ [Concern(typeof (UnitOfWork))]
+ public class when_attempting_to_commit_a_unit_of_work : when_a_unit_of_work_has_no_changes
+ {
+ it should_not_flush_the_session = () => session.was_not_told_to(x => x.flush());
+ because b = () => sut.commit();
+ }
+
+ [Concern(typeof (UnitOfWork))]
+ public class when_disposing_of_a_unit_of_work : behaves_like_unit_of_work
+ {
+ it should_dispose_the_session = () => session.was_told_to(x => x.Dispose());
+ it should_remove_the_session_from_the_current_context = () => session_context.was_told_to(x => x.remove(key));
+ because b = () => sut.Dispose();
+ }
+}
\ No newline at end of file
product/MoMoney.Service/MoMoney.Service.csproj
@@ -98,6 +98,11 @@
<Compile Include="Infrastructure\Security\IsInRole.cs" />
<Compile Include="Infrastructure\Security\IsInRoleSpecs.cs" />
<Compile Include="Infrastructure\Security\Role.cs" />
+ <Compile Include="Infrastructure\Transactions\EmptyUnitOfWork.cs" />
+ <Compile Include="Infrastructure\Transactions\UnitOfWork.cs" />
+ <Compile Include="Infrastructure\Transactions\UnitOfWorkFactory.cs" />
+ <Compile Include="Infrastructure\Transactions\UnitOfWorkFactorySpecs.cs" />
+ <Compile Include="Infrastructure\Transactions\UnitOfWorkSpecs.cs" />
<Compile Include="Infrastructure\Updating\CancelUpdate.cs" />
<Compile Include="Infrastructure\Updating\CancelUpdateSpecs.cs" />
<Compile Include="Infrastructure\Updating\CurrentDeployment.cs" />
@@ -120,9 +125,6 @@
<Name>MoMoney.DTO</Name>
</ProjectReference>
</ItemGroup>
- <ItemGroup>
- <Content Include="Application\Public\AddNewIncomeCommand.svc" />
- </ItemGroup>
<ItemGroup>
<Folder Include="Domain\" />
<Folder Include="Infrastructure\Core\" />
product/MyMoney/boot/container/registration/proxy_configuration/ServiceLayerConfiguration.cs
@@ -1,7 +1,6 @@
using System.Security.Principal;
using Gorilla.Commons.Infrastructure;
using Gorilla.Commons.Infrastructure.Castle.DynamicProxy;
-using Gorilla.Commons.Infrastructure.Castle.DynamicProxy.Interceptors;
using Gorilla.Commons.Utility.Core;
using Gorilla.Commons.Utility.Extensions;
using MoMoney.Service.Infrastructure.Security;
product/MyMoney/boot/container/registration/proxy_configuration/UnitOfWorkInterceptor.cs
@@ -0,0 +1,33 @@
+using Castle.Core.Interceptor;
+using Gorilla.Commons.Infrastructure.Eventing;
+using Gorilla.Commons.Utility.Core;
+using MoMoney.Service.Infrastructure.Transactions;
+
+namespace MoMoney.boot.container.registration.proxy_configuration
+{
+ public interface IUnitOfWorkInterceptor : IInterceptor
+ {
+ }
+
+ public class UnitOfWorkInterceptor : IUnitOfWorkInterceptor
+ {
+ readonly IEventAggregator broker;
+ readonly IUnitOfWorkFactory factory;
+
+ public UnitOfWorkInterceptor(IEventAggregator broker, IUnitOfWorkFactory factory)
+ {
+ this.broker = broker;
+ this.factory = factory;
+ }
+
+ public void Intercept(IInvocation invocation)
+ {
+ using (var unit_of_work = factory.create())
+ {
+ invocation.Proceed();
+ broker.publish<ICallback<IUnitOfWork>>(x => x.run(unit_of_work));
+ unit_of_work.commit();
+ }
+ }
+ }
+}
\ No newline at end of file
product/MyMoney/boot/container/registration/auto_wire_components_in_to_the.cs
@@ -4,7 +4,6 @@ using Gorilla.Commons.Infrastructure;
using Gorilla.Commons.Infrastructure.Castle.Windsor.Configuration;
using Gorilla.Commons.Infrastructure.Reflection;
using Gorilla.Commons.Utility.Extensions;
-using MoMoney.Infrastructure.Container.Windsor.configuration;
namespace MoMoney.boot.container.registration
{
product/MyMoney/boot/container/registration/wire_up_the_data_access_components_into_the.cs
@@ -1,5 +1,4 @@
using Gorilla.Commons.Infrastructure;
-using Gorilla.Commons.Infrastructure.Castle.DynamicProxy.Interceptors;
using Gorilla.Commons.Infrastructure.Cloning;
using Gorilla.Commons.Infrastructure.Container;
using Gorilla.Commons.Infrastructure.Transactions;
@@ -8,6 +7,8 @@ using Gorilla.Commons.Utility.Extensions;
using MoMoney.boot.container.registration.proxy_configuration;
using MoMoney.DataAccess;
using MoMoney.DataAccess.Db40;
+using MoMoney.DataAccess.Transactions;
+using MoMoney.Service.Infrastructure.Transactions;
namespace MoMoney.boot.container.registration
{
product/MyMoney/boot/container/registration/wire_up_the_infrastructure_in_to_the.cs
@@ -1,3 +1,4 @@
+using System.Collections;
using System.ComponentModel;
using System.Deployment.Application;
using Gorilla.Commons.Infrastructure;
@@ -30,7 +31,7 @@ namespace MoMoney.boot.container.registration
registry.transient(typeof (ITrackerEntryMapper<>), typeof (TrackerEntryMapper<>));
registry.transient(typeof (IKey<>), typeof (TypedKey<>));
registry.transient(typeof (IComponentFactory<>), typeof (ComponentFactory<>));
- registry.singleton<IContext, Context>();
+ registry.singleton<IContext>( ()=>new Context(new Hashtable()));
registry.singleton(() => AsyncOperationManager.SynchronizationContext);
registry.singleton<AsyncOperation>(() => AsyncOperationManager.CreateOperation(new object()));
product/MyMoney/boot/container/registration/wire_up_the_presentation_modules.cs
@@ -5,7 +5,7 @@ using Gorilla.Commons.Infrastructure.Reflection;
using Gorilla.Commons.Utility.Core;
using Gorilla.Commons.Utility.Extensions;
using MoMoney.boot.container.registration.proxy_configuration;
-using MoMoney.Modules.Core;
+using MoMoney.Presentation;
using MoMoney.Presentation.Core;
using MoMoney.Presentation.Model.Menu.File;
using MoMoney.Presentation.Model.Menu.Help;
product/MyMoney/boot/container/ComponentExclusionSpecification.cs
@@ -2,7 +2,7 @@ using System;
using Gorilla.Commons.Infrastructure.Castle.Windsor.Configuration;
using Gorilla.Commons.Utility.Extensions;
-namespace MoMoney.Infrastructure.Container.Windsor.configuration
+namespace MoMoney.boot.container
{
public class ComponentExclusionSpecification : IComponentExclusionSpecification
{
product/MyMoney/boot/container/ComponentExclusionSpecificationSpecs.cs
@@ -6,8 +6,8 @@ using developwithpassion.bdd.contexts;
using Gorilla.Commons.Infrastructure.Castle.Windsor.Configuration;
using Gorilla.Commons.Infrastructure.Container;
using Gorilla.Commons.Testing;
+using Gorilla.Commons.Utility.Core;
using MoMoney.Domain.Core;
-using MoMoney.Infrastructure.Container.Windsor.configuration;
namespace MoMoney.boot.container
{
@@ -85,7 +85,7 @@ namespace MoMoney.boot.container
public class FakeEntity : IEntity
{
- public Guid id
+ public Id<Guid> id
{
get { throw new NotImplementedException(); }
}
product/MyMoney/boot/container/type_extensions.cs
@@ -4,7 +4,7 @@ using Gorilla.Commons.Infrastructure.Container;
using Gorilla.Commons.Utility.Core;
using MoMoney.Domain.Core;
-namespace MoMoney.Infrastructure.Container.Windsor.configuration
+namespace MoMoney.boot.container
{
public static class type_extensions
{
product/MyMoney/Modules/Core/LoadPresentationModulesCommand.cs
@@ -1,6 +1,7 @@
using Gorilla.Commons.Infrastructure.Threading;
using Gorilla.Commons.Utility.Core;
using Gorilla.Commons.Utility.Extensions;
+using MoMoney.Presentation;
namespace MoMoney.Modules.Core
{
product/MyMoney/Modules/Core/LoadPresentationModulesCommandSpecs.cs
@@ -2,6 +2,7 @@ using developwithpassion.bdd.contexts;
using Gorilla.Commons.Infrastructure.Threading;
using Gorilla.Commons.Testing;
using Gorilla.Commons.Utility.Core;
+using MoMoney.Presentation;
namespace MoMoney.Modules.Core
{
product/MyMoney/Modules/ApplicationMenuModule.cs
@@ -1,5 +1,5 @@
using Gorilla.Commons.Infrastructure.Eventing;
-using MoMoney.Modules.Core;
+using MoMoney.Presentation;
using MoMoney.Presentation.Model.Menu;
using MoMoney.Presentation.Model.messages;
using MoMoney.Presentation.Presenters.Commands;
product/MyMoney/Modules/ApplicationShellModule.cs
@@ -1,4 +1,4 @@
-using MoMoney.Modules.Core;
+using MoMoney.Presentation;
using MoMoney.Presentation.Presenters.Commands;
using MoMoney.Presentation.Presenters.Shell;
product/MyMoney/Modules/DatabaseModule.cs
@@ -1,6 +1,6 @@
using Gorilla.Commons.Infrastructure.Eventing;
using MoMoney.DataAccess;
-using MoMoney.Modules.Core;
+using MoMoney.Presentation;
namespace MoMoney.Modules
{
product/MyMoney/Modules/GettingStartedModule.cs
@@ -1,5 +1,5 @@
using Gorilla.Commons.Infrastructure.Eventing;
-using MoMoney.Modules.Core;
+using MoMoney.Presentation;
using MoMoney.Presentation.Model.messages;
using MoMoney.Presentation.Presenters.Commands;
using MoMoney.Presentation.Presenters.Shell;
product/MyMoney/Modules/MainMenuModule.cs
@@ -1,5 +1,5 @@
using Gorilla.Commons.Infrastructure.Eventing;
-using MoMoney.Modules.Core;
+using MoMoney.Presentation;
using MoMoney.Presentation.Model.messages;
using MoMoney.Presentation.Presenters.Commands;
using MoMoney.Presentation.Presenters.Navigation;
product/MyMoney/Modules/ToolbarModule.cs
@@ -1,5 +1,5 @@
using Gorilla.Commons.Infrastructure.Eventing;
-using MoMoney.Modules.Core;
+using MoMoney.Presentation;
using MoMoney.Presentation.Model.Menu;
using MoMoney.Presentation.Model.messages;
using MoMoney.Presentation.Presenters.Commands;
product/MyMoney/MyMoney.csproj
@@ -151,6 +151,7 @@
<Compile Include="boot\container\registration\proxy_configuration\SecuringProxySpecs.cs" />
<Compile Include="boot\container\registration\proxy_configuration\ServiceLayerConfiguration.cs" />
<Compile Include="boot\container\registration\proxy_configuration\SynchronizedConfiguration.cs" />
+ <Compile Include="boot\container\registration\proxy_configuration\UnitOfWorkInterceptor.cs" />
<Compile Include="boot\container\registration\wire_up_the_infrastructure_in_to_the.cs" />
<Compile Include="boot\container\tear_down_the_container.cs" />
<Compile Include="boot\container\registration\wire_up_the_data_access_components_into_the.cs" />