Commit 80961f7

mokhan <mokhan@ce5e1baf-6525-42e4-a1b2-857ea38da20a>
2009-04-02 03:52:51
ensuring support to add items loaded from database into the cache.
git-svn-id: https://svn.xp-dev.com/svn/mokhan-mo.money@133 ce5e1baf-6525-42e4-a1b2-857ea38da20a
1 parent 6f41a5d
Changed files (8)
trunk/product/MyMoney/Infrastructure/transactions2/IDatabase.cs
@@ -1,9 +1,10 @@
 using System.Collections.Generic;
+using MoMoney.Domain.Core;
 
 namespace MoMoney.Infrastructure.transactions2
 {
     public interface IDatabase
     {
-        IEnumerable<T> fetch_all<T>();
+        IEnumerable<T> fetch_all<T>() where T : IEntity;
     }
 }
\ No newline at end of file
trunk/product/MyMoney/Infrastructure/transactions2/ITransaction.cs
@@ -5,6 +5,7 @@ namespace MoMoney.Infrastructure.transactions2
     public interface ITransaction
     {
         void add_transient<T>(T entity) where T : IEntity;
+        void add_dirty<T>(T modified) where T : IEntity;
         void commit_changes();
         void rollback_changes();
     }
trunk/product/MyMoney/Infrastructure/transactions2/Session.cs
@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.Linq;
 using MoMoney.Domain.Core;
 using MoMoney.Infrastructure.caching;
 using MoMoney.Utility.Extensions;
@@ -8,7 +9,8 @@ namespace MoMoney.Infrastructure.transactions2
 {
     public interface ISession : IDisposable
     {
-        IEnumerable<T> all<T>();
+        IEntity find<T>(Guid guid) where T : IEntity;
+        IEnumerable<T> all<T>() where T : IEntity;
         void save<T>(T entity) where T : IEntity;
         void update<T>(T entity) where T : IEntity;
         void flush();
@@ -18,7 +20,7 @@ namespace MoMoney.Infrastructure.transactions2
     {
         readonly IIdentityMapFactory factory;
         ITransaction transaction;
-        IDatabase database;
+        readonly IDatabase database;
         readonly IDictionary<Type, object> identity_maps;
 
         public Session(IIdentityMapFactory factory, ITransaction transaction, IDatabase database)
@@ -29,9 +31,26 @@ namespace MoMoney.Infrastructure.transactions2
             identity_maps = new Dictionary<Type, object>();
         }
 
-        public IEnumerable<T> all<T>()
+        public IEntity find<T>(Guid id) where T : IEntity
         {
-            return get_identity_map_for<T>().all().join_with(database.fetch_all<T>());
+            var identity_map = get_identity_map_for<T>();
+            if (identity_map.contains_an_item_for(id))
+            {
+                return identity_map.item_that_belongs_to(id);
+            }
+            var entity = database.fetch_all<T>().Single(x => x.Id.Equals(id));
+            identity_map.add(id, entity);
+            return entity;
+        }
+
+        public IEnumerable<T> all<T>() where T : IEntity
+        {
+            var identity_map = get_identity_map_for<T>();
+            var uncached_items = database
+                .fetch_all<T>()
+                .where(x => !identity_map.contains_an_item_for(x.Id));
+            uncached_items.each(x => identity_map.add(x.Id, x));
+            return uncached_items.join_with(identity_map.all());
         }
 
         public void save<T>(T entity) where T : IEntity
@@ -43,6 +62,7 @@ namespace MoMoney.Infrastructure.transactions2
         public void update<T>(T entity) where T : IEntity
         {
             get_identity_map_for<T>().update_the_item_for(entity.Id, entity);
+            transaction.add_dirty(entity);
         }
 
         public void flush()
trunk/product/MyMoney/Infrastructure/transactions2/SessionSpecs.cs
@@ -72,42 +72,13 @@ namespace MoMoney.Infrastructure.transactions2
         because b = () => sut.Dispose();
     }
 
-    public class when_retrieving_an_all_the_items_from_a_session_it_retrieve_all_the_items_from_the_cache :
-        behaves_like_session
-    {
-        it should_return_all_the_items_currently_loaded_in_the_cache = () => results.should_contain(entity);
-
-        it should_load_all_the_items_from_the_database = () =>
-                                                             {
-                                                                 ///?how
-                                                             };
-
-        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(factory).is_told_to(x => x.create_for<ITestEntity>()).it_will_return(map);
-                            when_the(map).is_told_to(x => x.all()).it_will_return(entity);
-                        };
-
-        because b = () =>
-                        {
-                            sut.save(entity);
-                            results = sut.all<ITestEntity>();
-                        };
-
-        static IEnumerable<ITestEntity> results;
-        static ITestEntity entity;
-        static Guid guid;
-        static IIdentityMap<Guid, ITestEntity> map;
-    }
 
     public class when_updating_a_persistent_entity : behaves_like_session
     {
-        it should_update_the_item_in_the_map = () => map.was_told_to(x => x.update_the_item_for(guid,modified));
+        it should_update_the_item_in_the_map = () => map.was_told_to(x => x.update_the_item_for(guid, modified));
+
+        it should_mark_the_item_as_changed_with_the_transaction =
+            () => transaction.was_told_to(x => x.add_dirty(modified));
 
         context c = () =>
                         {
@@ -135,6 +106,79 @@ namespace MoMoney.Infrastructure.transactions2
         static IIdentityMap<Guid, ITestEntity> map;
     }
 
+    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(factory).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 Guid id;
+        static Guid id_of_the_uncached_item;
+        static ITestEntity cached_item;
+        static ITestEntity database_item;
+        static IIdentityMap<Guid, ITestEntity> identity_map;
+        static ITestEntity uncached_item;
+    }
+
+    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(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(factory).is_told_to(x => x.create_for<ITestEntity>())
+                                .it_will_return(map);
+                        };
+
+        because b = () => { result = sut.find<ITestEntity>(id); };
+
+        static Guid id;
+        static IEntity result;
+        static ITestEntity correct_item;
+        static ITestEntity wrong_item;
+        static IIdentityMap<Guid, ITestEntity> map;
+    }
 
     public interface ITestEntity : IEntity
     {
trunk/product/MyMoney/Presentation/Views/dialogs/SaveChangesView.cs
@@ -1,13 +1,11 @@
 using System;
 using System.Windows.Forms;
-using JetBrains.Annotations;
 using MoMoney.Presentation.Model.Menu.File.Commands;
 using MoMoney.Presentation.Resources;
 using MoMoney.Presentation.Views.core;
 
 namespace MoMoney.Presentation.Views.dialogs
 {
-    [UsedImplicitly]
     public partial class SaveChangesView : ApplicationWindow, ISaveChangesView
     {
         bool can_be_closed;
@@ -24,7 +22,6 @@ namespace MoMoney.Presentation.Views.dialogs
                 .create_tool_tip_for("Cancel", "Go back.", cancel_button);
         }
 
-
         public void attach_to(ISaveChangesPresenter presenter)
         {
             save_button.Click += (sender, e) => execute(presenter.save);
trunk/product/MyMoney/Utility/Extensions/EnumerableExtensions.cs
@@ -6,6 +6,11 @@ namespace MoMoney.Utility.Extensions
 {
     public static class EnumerableExtensions
     {
+        public static IEnumerable<T> where<T>(this IEnumerable<T> items, Func<T, bool> condition_is_met)
+        {
+            return null == items ? new List<T>() : items.Where(condition_is_met);
+        }
+
         public static IList<T> databind<T>(this IEnumerable<T> items_to_bind_to)
         {
             return items_to_bind_to.ToList();
@@ -15,12 +20,7 @@ namespace MoMoney.Utility.Extensions
                                                      Predicate<T> criteria_to_satisfy)
         {
             foreach (var item in items_to_peek_in_to ?? new List<T>())
-            {
-                if (item.satisfies(criteria_to_satisfy))
-                {
-                    yield return item;
-                }
-            }
+                if (item.satisfies(criteria_to_satisfy)) yield return item;
         }
 
         public static IEnumerable<T> sorted_using<T>(this IEnumerable<T> items_to_sort, IComparer<T> sorting_algorithm)
trunk/product/MyMoney/Utility/Extensions/querying_extensions.cs
@@ -1,14 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace MoMoney.Utility.Extensions
-{
-    public static class querying_extensions
-    {
-        public static IEnumerable<T> where<T>(this IEnumerable<T> items, Func<T, bool> condition_is_met)
-        {
-            return items.Where(condition_is_met);
-        }
-    }
-}
\ No newline at end of file
trunk/product/MyMoney/MyMoney.csproj
@@ -654,7 +654,6 @@
     <Compile Include="Utility\Extensions\mapping_extensions_specs.cs" />
     <Compile Include="Utility\Extensions\numeric_conversions.cs" />
     <Compile Include="Utility\Extensions\numeric_conversions_specs.cs" />
-    <Compile Include="Utility\Extensions\querying_extensions.cs" />
     <Compile Include="Utility\Extensions\SpecificationExtensionsSpecs.cs" />
     <Compile Include="Utility\Extensions\specification_extensions.cs" />
     <Compile Include="Infrastructure\Logging\ILogFactory.cs" />