Commit 80961f7
Changed files (8)
trunk
product
MyMoney
Infrastructure
transactions2
Presentation
Views
dialogs
Utility
Extensions
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" />