Skip to content

Commit

Permalink
fk, passing tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Leonardo Porro committed Jan 29, 2024
1 parent 291ed2a commit 455c689
Show file tree
Hide file tree
Showing 22 changed files with 133 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,23 @@
<NeutralLanguage />
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageIcon>logo.png</PackageIcon>
<PackageId>Detached.Mappers.EntityFramework</PackageId> <PackageReadmeFile>Readme.MD</PackageReadmeFile>
<PackageId>Detached.Mappers.EntityFramework</PackageId>
<PackageReadmeFile>Readme.MD</PackageReadmeFile>
</PropertyGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net6.0'">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.*" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.*" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net7.0'">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.*" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.*" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.*" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.*" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
namespace Detached.Mappers.EntityFramework.TypeMappers
{
public class AggregationEntityTypeMapper<TSource, TTarget, TKey> : EntityTypeMapper<TSource, TTarget, TKey>
where TSource : class
where TTarget : class
where TKey : IEntityKey
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
namespace Detached.Mappers.EntityFramework.TypeMappers
{
public abstract class EntityTypeMapper<TSource, TTarget, TKey> : TypeMapper<TSource, TTarget>
where TSource : class
where TTarget : class
where TKey : IEntityKey
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ public class EntityTypeMapperFactory : ITypeMapperFactory
{
public bool CanCreate(Mapper mapper, TypePair typePair)
{
return typePair.SourceType.IsComplexOrEntity()
&& typePair.TargetType.IsEntity()
return typePair.TargetType.IsEntity()
&& typePair.TargetType.IsConcrete();
}

Expand Down
1 change: 1 addition & 0 deletions src/Detached.Mappers/Detached.Mappers.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<ItemGroup>
<PackageReference Include="Detached.RuntimeTypes" Version="8.0.0" />
<PackageReference Include="Detached.PatchTypes" Version="8.0.0" />
<PackageReference Include="Humanizer" Version="2.14.1" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.1" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
Expand Down
12 changes: 8 additions & 4 deletions src/Detached.Mappers/MapperOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using Detached.Mappers.TypeMappers.POCO.Nullable;
using Detached.Mappers.TypeMappers.POCO.Primitive;
using Detached.Mappers.TypePairs;
using Detached.Mappers.TypePairs.Conventions;
using Detached.Mappers.Types;
using Detached.Mappers.Types.Class;
using Detached.Mappers.Types.Class.Builder;
Expand Down Expand Up @@ -78,8 +79,7 @@ public MapperOptions()
new NullableTypeMapperFactory(),
new InheritedTypeMapperFactory(),
new EntityCollectionTypeMapperFactory(),
new EntityTypeMapperFactory(),
new KeyToComplexTypeMapperFactory()
new EntityTypeMapperFactory()
};

ConcreteTypes = new Dictionary<Type, Type>
Expand Down Expand Up @@ -111,7 +111,11 @@ public MapperOptions()
new NullableTypeBinder()
};

PropertyNameConventions = new List<IPropertyNameConvention>();
MemberNameConventions = new List<IMemberNameConvention>
{
new ForeignKeyMemberNameConvention(),
new DefaultMemberNameConvention()
};
}

public virtual HashSet<Type> Primitives { get; }
Expand All @@ -126,7 +130,7 @@ public MapperOptions()

public virtual List<ITypeConvention> TypeConventions { get; }

public virtual List<IPropertyNameConvention> PropertyNameConventions { get; }
public virtual List<IMemberNameConvention> MemberNameConventions { get; }

public virtual Dictionary<Type, Type> ConcreteTypes { get; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ namespace Detached.Mappers.TypeMappers.Entity.Collection
public class EntityCollectionTypeMapper<TSource, TSourceItem, TTarget, TTargetItem, TKey> : TypeMapper<TSource, TTarget>
where TSource : IEnumerable<TSourceItem>
where TTarget : ICollection<TTargetItem>
where TSourceItem : class
where TTargetItem : class
where TKey : IEntityKey
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public bool CanCreate(Mapper mapper, TypePair typePair)
IType sourceItemType = mapper.Options.GetType(typePair.TargetType.ItemClrType);
IType targetItemType = mapper.Options.GetType(typePair.TargetType.ItemClrType);

return targetItemType.IsEntity() && sourceItemType.IsComplexOrEntity();
return targetItemType.IsEntity() && (sourceItemType.IsComplexOrEntity() || sourceItemType.IsPrimitive());
}

return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ namespace Detached.Mappers.TypeMappers.Entity.Collection
public class EntityListTypeMapper<TSource, TSourceItem, TTarget, TTargetItem, TKey> : TypeMapper<TSource, TTarget>
where TSource : IEnumerable<TSourceItem>
where TTarget : IList<TTargetItem>
where TSourceItem : class
where TTargetItem : class
where TKey : IEntityKey
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Detached.Mappers.Types;

namespace Detached.Mappers.TypePairs.Conventions
{
public class CamelCaseMemberNameConvention : IMemberNameConvention
{
public string GetSourceMemberName(string targetMemberName, IType sourceType, IType targetType, MapperOptions mapperOptions)
{
return char.ToLower(targetMemberName[0]) + targetMemberName.Substring(1);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Detached.Mappers.Types;

namespace Detached.Mappers.TypePairs.Conventions
{
public class DefaultMemberNameConvention : IMemberNameConvention
{
public string GetSourceMemberName(string targetMemberName, IType sourceType, IType targetType, MapperOptions mapperOptions)
{
return targetMemberName;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using Detached.Mappers.Types;
using Humanizer;

namespace Detached.Mappers.TypePairs.Conventions
{
public class ForeignKeyMemberNameConvention : IMemberNameConvention
{
public string GetSourceMemberName(string targetMemberName, IType sourceType, IType targetType, MapperOptions mapperOptions)
{
string memberName = null;

if (targetType.IsEntity())
{
var key = targetType.GetKeyMember();

if (key != null)
{
var member = targetType.GetMember(targetMemberName);
var memberType = mapperOptions.GetType(member.ClrType);

if (memberType.IsCollection())
{
memberName = targetMemberName.Singularize(false) + key.Name.Pluralize(false);
}
else
{
memberName = targetMemberName + key.Name;
}
}
}

return memberName;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Detached.Mappers.Types;

namespace Detached.Mappers.TypePairs.Conventions
{
public interface IMemberNameConvention
{
string GetSourceMemberName(string targetMemberName, IType sourceType, IType targetType, MapperOptions mapperOptions);
}
}
2 changes: 1 addition & 1 deletion src/Detached.Mappers/TypePairs/ITypePairFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ namespace Detached.Mappers.TypePairs
{
public interface ITypePairFactory
{
TypePair Create(MapperOptions mapperOptions, IType sourceType, IType targetType, TypePairMember sourceMember);
TypePair Create(MapperOptions mapperOptions, IType sourceType, IType targetType, TypePairMember parentMember);
}
}
37 changes: 18 additions & 19 deletions src/Detached.Mappers/TypePairs/TypePairFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ public TypePair Create(MapperOptions mapperOptions, IType sourceType, IType targ

if (memberNames != null)
{
var keyMember = targetType.GetKeyMember();

foreach (string targetMemberName in memberNames)
{
ITypeMember targetMember = targetType.GetMember(targetMemberName);
Expand All @@ -26,18 +24,7 @@ public TypePair Create(MapperOptions mapperOptions, IType sourceType, IType targ
member.TargetType = targetType;
member.SourceType = sourceType;
member.TargetMember = targetMember;

string sourceMemberName = GetSourcePropertyName(mapperOptions, sourceType, targetType, targetMemberName);

ITypeMember sourceMember = sourceType.GetMember(sourceMemberName);

if (sourceMember == null && keyMember != null)
{
string keyName = targetMemberName + keyMember.Name;
sourceMember = sourceType.GetMember(keyName);
}

member.SourceMember = sourceMember;
member.SourceMember = GetSourceMember(targetMemberName, sourceType, targetType, mapperOptions);

typePair.Members.Add(targetMemberName, member);
}
Expand All @@ -47,14 +34,26 @@ public TypePair Create(MapperOptions mapperOptions, IType sourceType, IType targ
return typePair;
}

public string GetSourcePropertyName(MapperOptions mapperOptions, IType sourceType, IType targetType, string memberName)
public ITypeMember GetSourceMember(string targetMemberName, IType sourceType, IType targetType, MapperOptions mapperOptions)
{
for (int i = mapperOptions.PropertyNameConventions.Count - 1; i >= 0; i--)
ITypeMember result = null;

for (int i = mapperOptions.MemberNameConventions.Count - 1; i >= 0; i--)
{
memberName = mapperOptions.PropertyNameConventions[i].GetSourcePropertyName(sourceType, targetType, memberName);
var convention = mapperOptions.MemberNameConventions[i];

var sourceMemberName = convention.GetSourceMemberName(targetMemberName, sourceType, targetType, mapperOptions);

if (sourceMemberName != null)
{
result = sourceType.GetMember(sourceMemberName);

if (result != null)
break;
}
}

return memberName;
return result;
}
}
}
}
11 changes: 11 additions & 0 deletions src/Detached.Mappers/TypePairs/TypePairMember.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,16 @@ public class TypePairMember
public ITypeMember TargetMember { get; set; }

public AnnotationCollection Annotations { get; set; } = new();

public override string ToString()
{
string sourceName = SourceMember == null
? "null"
: SourceMember.Name + ": " + SourceMember.ClrType.GetFriendlyName();

string targetName = TargetMember.ClrType.GetFriendlyName();

return $"TypePairMember ({sourceName} -> {targetName})";
}
}
}
2 changes: 1 addition & 1 deletion src/Detached.Mappers/Types/Class/ClassType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,6 @@ public virtual Expression BuildNewExpression(Expression context, Expression disc
return Import(Constructor, context);
}

public override string ToString() => $"{ClrType.GetFriendlyName()} (ClassType)";
public override string ToString() => $"ClassType ({ClrType.GetFriendlyName()})";
}
}
2 changes: 1 addition & 1 deletion src/Detached.Mappers/Types/Class/ClassTypeMember.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,6 @@ public virtual Expression BuildTryGetExpression(Expression instance, Expression
return Import(TryGetter, instance, outVar, context);
}

public override string ToString() => $"{Name} [{ClrType.GetFriendlyName()}] (MemberOptions)";
public override string ToString() => $"ClassTypeMember ({Name}: {ClrType.GetFriendlyName()})";
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
using Detached.Mappers.EntityFramework.Extensions;
using Detached.Mappers.EntityFramework.Tests.Fixture;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Threading.Tasks;
using Xunit;

namespace Detached.Mappers.EntityFramework.Tests
{
public class KeyToEntityTests
public class ForeignKeyTests
{
//[Fact]
public async Task map_key_to_entity()
[Fact]
public async Task map_fk_to_entity()
{
var dbContext = await TestDbContext.Create<KeyToEntityDbContext>();

Expand All @@ -22,12 +23,20 @@ public async Task map_key_to_entity()
{
Id = 1,
Name = "test user",
ChildId = 2
ChildId = 2,
ChildIds = new[] { 1, 2 }
});

Assert.NotNull(result.Child);
Assert.Equal(2, result.Child.Id);
Assert.Equal("Child 2", result.Child.Name);

Assert.NotNull(result.Children);
Assert.Equal(1, result.Children[0].Id);
Assert.Equal("Child 1", result.Children[0].Name);

Assert.Equal(2, result.Children[1].Id);
Assert.Equal("Child 2", result.Children[1].Name);
}

public class ParentEntity
Expand All @@ -37,6 +46,8 @@ public class ParentEntity
public string Name { get; set; }

public ChildEntity Child { get; set; }

public List<ChildEntity> Children { get; set; }
}

public class ChildEntity
Expand Down
4 changes: 2 additions & 2 deletions test/Detached.Mappers.Json.Tests/JsonTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using Detached.Mappers.Json.Tests.Fixture;
using Detached.Mappers.Types.Conventions;
using Detached.Mappers.TypePairs.Conventions;
using System.Text.Json.Nodes;
using Xunit;

Expand All @@ -22,7 +22,7 @@ public void map_json_to_entity()
// create options. Json lib is a separate package to avoid adding System.Text.Json dependency to the main lib, call WithJson() to integrate.
MapperOptions mapperOptions = new MapperOptions().WithJson();

mapperOptions.PropertyNameConventions.Add(new CamelCasePropertyNameConvention());
mapperOptions.MemberNameConventions.Add(new CamelCaseMemberNameConvention());

// create the mapper.
Mapper mapper = new Mapper(mapperOptions);
Expand Down

0 comments on commit 455c689

Please sign in to comment.