Skip to content

Commit

Permalink
writability of ExpressionToProperty is checked during mapper building
Browse files Browse the repository at this point in the history
  • Loading branch information
maksimkim committed Sep 1, 2013
1 parent 702a86b commit 3b63840
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
using EntityFunctors.Extensions;
using EntityFunctors.Associations.Fluent;

public class ExpressionToPropertyAssociation<TSource, TTarget, TProperty>
public class ExpressionToPropertyAssociation<TSource, TTarget, TProperty>
: IMappingAssociation, IAccessable
where TSource : class
where TTarget : class, new()
Expand All @@ -24,11 +24,13 @@ public ExpressionToPropertyAssociation(Expression<Func<TSource, TProperty>> sour
{
Contract.Assert(source != null);
Contract.Assert(target != null);
Contract.Assert(source.ReturnType == target.ReturnType);


PropertyInfo prop;
Contract.Assert(target.Body.TryGetProperty(out prop));

if (source.Body is MemberExpression && (source.Body as MemberExpression).Expression == source.Parameters[0])
throw new ArgumentException("ExpressionToProperty association cannot be used for mapping properties");

Source = source;
Target = target;

Expand All @@ -44,9 +46,6 @@ public void ReadOnly()

public void WriteOnly()
{
if (!IsPropertyChain(Source))
throw new InvalidOperationException("Only property chain expression can be set writable");

Direction = MappingDirection.Write;
}

Expand All @@ -57,9 +56,6 @@ public void Read()

public void Write()
{
if (!IsPropertyChain(Source))
throw new InvalidOperationException("Only property chain expression can be set writable");

AddDirection(MappingDirection.Write);
}

Expand All @@ -68,25 +64,5 @@ private void AddDirection(MappingDirection val)
if ((Direction & val) != val)
Direction |= val;
}

private bool IsPropertyChain(LambdaExpression expression)
{
var current = expression.Body;

while (current != null)
{
PropertyInfo p;

if (current.NodeType == ExpressionType.Parameter)
return true;

if (!current.TryGetProperty(out p))
return false;

current = (current as MemberExpression).Expression;
}

return true;
}
}
}
3 changes: 2 additions & 1 deletion src/EntityFunctors/Cfg/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ namespace EntityFunctors.Cfg
{
public static class Config
{
private static IReflectionOptimizer _reflectionOptimizer { get; set; }
private static IReflectionOptimizer _reflectionOptimizer;

public static IReflectionOptimizer ReflectionOptimizer
{
get { return _reflectionOptimizer ?? (_reflectionOptimizer = new DefaultReflectionOptimizer()); }
set { _reflectionOptimizer = value; }
}
}
}
15 changes: 8 additions & 7 deletions src/EntityFunctors/Mappers/MapperFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,6 @@ public MapperFactory(params IAssociationProvider[] maps)

public MapperFactory(IEnumerable<IAssociationProvider> providers)
{
providers.ToDictionary(
m => m.Key,
m => m.Associations
);

_registry = providers.ToDictionary(p => p.Key, p => p.Associations);
}

Expand Down Expand Up @@ -80,7 +75,7 @@ private Expression BuildReaderBody(Expression @from, Type targetType, ParameterE
IEnumerable<IMappingAssociation> associations;

if (!_registry.TryGetValue(mapKey, out associations))
throw new NotImplementedException(
throw new InvalidOperationException(
string.Format("Unable to create mapper from {0} to {1}. Check appropriate mappings exist and loaded.", from.Type, targetType)
);

Expand Down Expand Up @@ -231,7 +226,7 @@ private Expression BuildWriterBody(Expression from, Expression to, ParameterExpr
IEnumerable<IMappingAssociation> associations;

if (!_registry.TryGetValue(mapKey, out associations))
throw new NotImplementedException(
throw new InvalidOperationException(
string.Format("Unable to create mapper from {0} to {1}. Check appropriate mappings exist and loaded.", @from.Type, to.Type)
);

Expand Down Expand Up @@ -274,6 +269,12 @@ private Expression BuildWriterItem(IMappingAssociation association, Expression f
}
else
{
PropertyInfo prop;
if (!acceptor.TryGetProperty(out prop))
throw new InvalidOperationException(
string.Format("Mapping from source:{0} to target:{1} marked as writable but source is not a property access expression", association.Source.Stringify(), association.Target.Stringify())
);

result = Expression.Assign(
acceptor,
converter == null ? donor : converter.TargetConverter.Expression.Apply(donor)
Expand Down
23 changes: 12 additions & 11 deletions src/EntityFunctors/TypeMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
using Associations.Impl;
using Extensions;

public class TypeMap<TSource, TTarget> : IAssociationProvider
where TSource : class
public class TypeMap<TSource, TTarget> : IAssociationProvider
where TSource : class
where TTarget : class, new()
{
private readonly IList<IMappingAssociation> _associations = new List<IMappingAssociation>();
Expand All @@ -33,9 +33,9 @@ Expression<Func<TTarget, TProperty>> target
}

protected IAccessable MapProperties<TSourceProperty, TTargetProperty>(
Expression<Func<TSource, TSourceProperty>> source,
Expression<Func<TSourceProperty, TTargetProperty>> converter,
Expression<Func<TTarget, TTargetProperty>> target,
Expression<Func<TSource, TSourceProperty>> source,
Expression<Func<TSourceProperty, TTargetProperty>> converter,
Expression<Func<TTarget, TTargetProperty>> target,
Expression<Func<TTargetProperty, TSourceProperty>> inverseConverter
)
{
Expand All @@ -47,7 +47,7 @@ Expression<Func<TTargetProperty, TSourceProperty>> inverseConverter
return association;
}

protected void MapExpressionToProperty<TProperty>(
protected IAccessable MapExpressionToProperty<TProperty>(
Expression<Func<TSource, TProperty>> source,
Expression<Func<TTarget, TProperty>> target
)
Expand All @@ -56,13 +56,14 @@ Expression<Func<TTarget, TProperty>> target

var association = new ExpressionToPropertyAssociation<TSource, TTarget, TProperty>(source, target);
_associations.Add(association);
return association;
}

protected IExpandable MapComponents<TSourceComponent, TTargetComponent>(
Expression<Func<TSource, TSourceComponent>> source,
Expression<Func<TTarget, TTargetComponent>> target
)
where TSourceComponent : class
)
where TSourceComponent : class
where TTargetComponent : class, new()
{
var association = new ComponentToComponentAssociation<TSource, TSourceComponent, TTarget, TTargetComponent>(source, target);
Expand All @@ -86,8 +87,8 @@ Expression<Func<TSourceItem, TTargetItem>> converter
protected IExpandable MapComponentCollections<TSourceItem, TTargetItem>(
Expression<Func<TSource, IEnumerable<TSourceItem>>> source,
Expression<Func<TTarget, IEnumerable<TTargetItem>>> target
)
where TSourceItem : class
)
where TSourceItem : class
where TTargetItem : class, new()
{
var association = new ComponentCollectionAssociation<TSource, TSourceItem, TTarget, TTargetItem>(source, target);
Expand All @@ -96,7 +97,7 @@ Expression<Func<TTarget, IEnumerable<TTargetItem>>> target
}

public virtual TypeMapKey Key { get; protected set; }

public IEnumerable<IMappingAssociation> Associations
{
get { return _associations; }
Expand Down
10 changes: 0 additions & 10 deletions test/EntityFunctors.Tests/ExpressionToPropertyAssociationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,6 @@ public void TestInverseMappingDoesNothing()
foo.Id.Should().Be(10);
}

[Test]
public void TestSettingWritablityThrowsOnInappropriateExpression()
{
Expression<Func<Foo, int>> source = _ => _.Id * _.Id;

var sut = new ExpressionToPropertyAssociation<Foo, Bar, int>(source, _ => _.Id);

((Action) sut.Write).ShouldThrow<InvalidOperationException>();
}

[Test]
public void TestInverseMappingAssignsOnWrite()
{
Expand Down

0 comments on commit 3b63840

Please sign in to comment.