Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,6 @@ jobs:
with:
dotnet-version: 10.0.x

- name: Install .NET Framework 4.6.2 Developer Pack
run: choco install netfx-4.6.2-devpack -y

- name: GitVersion Setup
uses: gittools/actions/gitversion/setup@v0
with:
Expand Down
5 changes: 1 addition & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ jobs:
with:
dotnet-version: 10.0.x

- name: Install .NET Framework 4.6.2 Developer Pack
run: choco install netfx-4.6.2-devpack -y

- name: Restore
run: dotnet restore

Expand All @@ -34,5 +31,5 @@ jobs:
- name: Test - net10 EF Core
run: dotnet test Mapify.NET.Tests.EFCore/Mapify.NET.Tests.EFCore.csproj -c Release --no-restore

- name: Test - net462
- name: Test - net472
run: dotnet test Mapify.NET.Tests.NetFx/Mapify.NET.Tests.NetFx.csproj -c Release --no-restore
45 changes: 30 additions & 15 deletions Mapify.NET.Tests.EFCore/MapifyEfCoreDefaultValueBehaviorTests.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
namespace Mapify.NET.Tests.EFCore;

public class MapifyEfCoreDefaultValueBehaviorTests {
public MapifyEfCoreDefaultValueBehaviorTests() {
Mapper.UseDefaultMapIfTypeMapIsMissing(false);
Mapper.ClearMappings();
}

[Fact]
public void CreateMap_ShouldKeepNull_ForNullableCollection_WhenSourceIsNull() {
var map = Mapper.CreateMap<EfCoreNullableCollectionSource, EfCoreNullableCollectionTarget>();
var mapify = new Mapify([new EfCoreNullableCollectionProfile()]);

var mapped = map.Map(new EfCoreNullableCollectionSource {
var mapped = mapify.Map<EfCoreNullableCollectionSource, EfCoreNullableCollectionTarget>(new EfCoreNullableCollectionSource {
Numbers = null
});

Expand All @@ -19,9 +14,9 @@ public void CreateMap_ShouldKeepNull_ForNullableCollection_WhenSourceIsNull() {

[Fact]
public void CreateMap_ShouldUseEmpty_ForNonNullableCollection_WhenSourceIsNull() {
var map = Mapper.CreateMap<EfCoreNullableCollectionSource, EfCoreNonNullableCollectionTarget>();
var mapify = new Mapify([new EfCoreNonNullableCollectionProfile()]);

var mapped = map.Map(new EfCoreNullableCollectionSource {
var mapped = mapify.Map<EfCoreNullableCollectionSource, EfCoreNonNullableCollectionTarget>(new EfCoreNullableCollectionSource {
Numbers = null
});

Expand All @@ -31,9 +26,9 @@ public void CreateMap_ShouldUseEmpty_ForNonNullableCollection_WhenSourceIsNull()

[Fact]
public void CreateMap_ShouldUseEmpty_ForRequiredCollection_WhenSourceIsNull() {
var map = Mapper.CreateMap<EfCoreNullableCollectionSource, EfCoreRequiredCollectionTarget>();
var mapify = new Mapify([new EfCoreRequiredCollectionProfile()]);

var mapped = map.Map(new EfCoreNullableCollectionSource {
var mapped = mapify.Map<EfCoreNullableCollectionSource, EfCoreRequiredCollectionTarget>(new EfCoreNullableCollectionSource {
Numbers = null
});

Expand All @@ -43,9 +38,9 @@ public void CreateMap_ShouldUseEmpty_ForRequiredCollection_WhenSourceIsNull() {

[Fact]
public void CreateMap_ShouldPreserveInitializer_ForNonNullableCollection_WhenSourcePropertyIsMissing() {
var map = Mapper.CreateMap<EfCoreSourceWithoutCollection, EfCoreInitializedCollectionTarget>();
var mapify = new Mapify([new EfCoreInitializedCollectionProfile()]);

var mapped = map.Map(new EfCoreSourceWithoutCollection {
var mapped = mapify.Map<EfCoreSourceWithoutCollection, EfCoreInitializedCollectionTarget>(new EfCoreSourceWithoutCollection {
Id = 5
});

Expand All @@ -55,9 +50,9 @@ public void CreateMap_ShouldPreserveInitializer_ForNonNullableCollection_WhenSou

[Fact]
public void CreateMap_ShouldUseEmpty_ForUninitializedNonNullableCollection_WhenSourcePropertyIsMissing() {
var map = Mapper.CreateMap<EfCoreSourceWithoutCollection, EfCoreUninitializedCollectionTarget>();
var mapify = new Mapify([new EfCoreUninitializedCollectionProfile()]);

var mapped = map.Map(new EfCoreSourceWithoutCollection {
var mapped = mapify.Map<EfCoreSourceWithoutCollection, EfCoreUninitializedCollectionTarget>(new EfCoreSourceWithoutCollection {
Id = 5
});

Expand Down Expand Up @@ -95,4 +90,24 @@ private sealed class EfCoreUninitializedCollectionTarget {
public int Id { get; set; }
public List<int> Numbers { get; set; } = null!;
}

private sealed class EfCoreNullableCollectionProfile : MapifyProfile {
protected override void Configure() => CreateMap<EfCoreNullableCollectionSource, EfCoreNullableCollectionTarget>();
}

private sealed class EfCoreNonNullableCollectionProfile : MapifyProfile {
protected override void Configure() => CreateMap<EfCoreNullableCollectionSource, EfCoreNonNullableCollectionTarget>();
}

private sealed class EfCoreRequiredCollectionProfile : MapifyProfile {
protected override void Configure() => CreateMap<EfCoreNullableCollectionSource, EfCoreRequiredCollectionTarget>();
}

private sealed class EfCoreInitializedCollectionProfile : MapifyProfile {
protected override void Configure() => CreateMap<EfCoreSourceWithoutCollection, EfCoreInitializedCollectionTarget>();
}

private sealed class EfCoreUninitializedCollectionProfile : MapifyProfile {
protected override void Configure() => CreateMap<EfCoreSourceWithoutCollection, EfCoreUninitializedCollectionTarget>();
}
}
39 changes: 39 additions & 0 deletions Mapify.NET.Tests.EFCore/MapifyEfCoreIgnoreMarkerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,38 @@ public void IgnoreMarker_ShouldExcludeIgnoredPropertyFromEfCoreSqlProjection() {
Assert.Null(projected.IgnoredFromDb);
}

[Fact]
public void IgnoreMarker_ShouldExcludeIgnoredPropertyFromEfCoreSqlProjection_WhenUsingDslMap() {
using var connection = new SqliteConnection("Data Source=:memory:");
connection.Open();

var options = new DbContextOptionsBuilder<EfCoreIgnoreMapifyContext>()
.UseSqlite(connection)
.Options;

using var db = new EfCoreIgnoreMapifyContext(options);
db.Database.EnsureCreated();

db.Set<EfCoreProjectionIgnoreEntity>().Add(new EfCoreProjectionIgnoreEntity {
Included = "included",
IgnoredFromDb = "ignored-db"
});
db.SaveChanges();

var mapify = new Mapify([
new EfCoreProjectionIgnoreDslProfile()
]);

var query = db.Set<EfCoreProjectionIgnoreEntity>().ProjectTo<EfCoreProjectionIgnoreDto>(mapify);
var sql = query.ToQueryString();

Assert.DoesNotContain("\"IgnoredFromDb\"", sql, StringComparison.Ordinal);

var projected = query.Single();
Assert.Equal("included", projected.Included);
Assert.Null(projected.IgnoredFromDb);
}

[Fact]
public void IgnoreMarker_ShouldExcludeIgnoredPropertyFromEfCoreSqlProjection_WhenUsingProjectTo() {
using var connection = new SqliteConnection("Data Source=:memory:");
Expand Down Expand Up @@ -124,4 +156,11 @@ protected override void Configure() {
});
}
}

private sealed class EfCoreProjectionIgnoreDslProfile : MapifyProfile {
protected override void Configure() {
CreateMap<EfCoreProjectionIgnoreEntity, EfCoreProjectionIgnoreDto>()
.Map(d => d.IgnoredFromDb, _ => Ignore<string?>());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,13 @@ public void CreateMap_ShouldWorkInEfCoreProjection_WithNestedInvokeForSingleAndC

db.SaveChanges();

var addressMap = Mapper.CreateMap<EfCoreAddress, EfCoreAddressDto>();
var phoneMap = Mapper.CreateMap<EfCorePhone, EfCorePhoneDto>();
var mapify = new Mapify([
new EfCoreAddressProfile(),
new EfCorePhoneProfile(),
new EfCorePersonInvokeProfile()
]);

var map = Mapper.CreateMap<EfCorePerson, EfCorePersonDto>(x => new EfCorePersonDto {
FullName = x.FirstName + " " + x.LastName,
HomeAddress = addressMap.Invoke(x.HomeAddress),
Phones = x.Phones.Select(p => phoneMap.Invoke(p)).ToList()
});
var map = mapify.GetRequiredMap<EfCorePerson, EfCorePersonDto>();

var result = db.People
.AsExpandable()
Expand Down Expand Up @@ -91,7 +90,8 @@ public void CreateMap_ShouldImplicitlyMapPrimitiveArraysAndCollections_InEfCoreP

db.SaveChanges();

var map = Mapper.CreateMap<EfCorePrimitiveCollectionsSource, EfCorePrimitiveCollectionsDto>();
var mapify = new Mapify([new EfCorePrimitiveCollectionsProfile()]);
var map = mapify.GetRequiredMap<EfCorePrimitiveCollectionsSource, EfCorePrimitiveCollectionsDto>();

var result = db.People
.OrderBy(x => x.Id)
Expand Down Expand Up @@ -160,4 +160,18 @@ public void InstanceMapify_ShouldImplicitlyUseExistingMapsForNestedAndArrayMembe
Assert.Equal("Manchester", result[1].HomeAddress.City);
Assert.Equal(new[] { "+44-200" }, result[1].Phones.Select(x => x.Number).ToArray());
}

private sealed class EfCorePersonInvokeProfile : MapifyProfile {
protected override void Configure() {
CreateMap<EfCorePerson, EfCorePersonDto>(x => new EfCorePersonDto {
FullName = x.FirstName + " " + x.LastName,
HomeAddress = UseMap<EfCoreAddress, EfCoreAddressDto>(x.HomeAddress),
Phones = UseMap<IEnumerable<EfCorePhone>, IEnumerable<EfCorePhoneDto>>(x.Phones).ToList()
});
}
}

private sealed class EfCorePrimitiveCollectionsProfile : MapifyProfile {
protected override void Configure() => CreateMap<EfCorePrimitiveCollectionsSource, EfCorePrimitiveCollectionsDto>();
}
}
1 change: 1 addition & 0 deletions Mapify.NET.Tests.NetFx/Mapify.NET.Tests.NetFx.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<PackageReference Include="EntityFramework" Version="6.5.1" />
<PackageReference Include="LinqKit.EntityFramework" Version="1.3.11" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.5" />
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
namespace Mapify.NET.Tests.NetFx;

public class MapifyNetFrameworkEf6DefaultValueBehaviorTests {
public MapifyNetFrameworkEf6DefaultValueBehaviorTests() {
Mapper.UseDefaultMapIfTypeMapIsMissing(false);
Mapper.ClearMappings();
}

[Fact]
public void CreateMap_ShouldKeepNull_ForNullableCollection_WhenSourceIsNull() {
var map = Mapper.CreateMap<Ef6NullableCollectionSource, Ef6NullableCollectionTarget>();
var mapify = new Mapify([new Ef6NullableCollectionProfile()]);

var mapped = map.Map(new Ef6NullableCollectionSource {
var mapped = mapify.Map<Ef6NullableCollectionSource, Ef6NullableCollectionTarget>(new Ef6NullableCollectionSource {
Numbers = null
});

Expand All @@ -19,9 +14,9 @@ public void CreateMap_ShouldKeepNull_ForNullableCollection_WhenSourceIsNull() {

[Fact]
public void CreateMap_ShouldUseEmpty_ForNonNullableCollection_WhenSourceIsNull() {
var map = Mapper.CreateMap<Ef6NullableCollectionSource, Ef6NonNullableCollectionTarget>();
var mapify = new Mapify([new Ef6NonNullableCollectionProfile()]);

var mapped = map.Map(new Ef6NullableCollectionSource {
var mapped = mapify.Map<Ef6NullableCollectionSource, Ef6NonNullableCollectionTarget>(new Ef6NullableCollectionSource {
Numbers = null
});

Expand All @@ -31,9 +26,9 @@ public void CreateMap_ShouldUseEmpty_ForNonNullableCollection_WhenSourceIsNull()

[Fact]
public void CreateMap_ShouldPreserveInitializer_ForNonNullableCollection_WhenSourcePropertyIsMissing() {
var map = Mapper.CreateMap<Ef6SourceWithoutCollection, Ef6InitializedCollectionTarget>();
var mapify = new Mapify([new Ef6InitializedCollectionProfile()]);

var mapped = map.Map(new Ef6SourceWithoutCollection {
var mapped = mapify.Map<Ef6SourceWithoutCollection, Ef6InitializedCollectionTarget>(new Ef6SourceWithoutCollection {
Id = 7
});

Expand All @@ -43,9 +38,9 @@ public void CreateMap_ShouldPreserveInitializer_ForNonNullableCollection_WhenSou

[Fact]
public void CreateMap_ShouldUseEmpty_ForUninitializedNonNullableCollection_WhenSourcePropertyIsMissing() {
var map = Mapper.CreateMap<Ef6SourceWithoutCollection, Ef6UninitializedCollectionTarget>();
var mapify = new Mapify([new Ef6UninitializedCollectionProfile()]);

var mapped = map.Map(new Ef6SourceWithoutCollection {
var mapped = mapify.Map<Ef6SourceWithoutCollection, Ef6UninitializedCollectionTarget>(new Ef6SourceWithoutCollection {
Id = 7
});

Expand Down Expand Up @@ -79,4 +74,20 @@ private class Ef6UninitializedCollectionTarget {
public int Id { get; set; }
public List<int> Numbers { get; set; } = null!;
}

private sealed class Ef6NullableCollectionProfile : MapifyProfile {
protected override void Configure() => CreateMap<Ef6NullableCollectionSource, Ef6NullableCollectionTarget>();
}

private sealed class Ef6NonNullableCollectionProfile : MapifyProfile {
protected override void Configure() => CreateMap<Ef6NullableCollectionSource, Ef6NonNullableCollectionTarget>();
}

private sealed class Ef6InitializedCollectionProfile : MapifyProfile {
protected override void Configure() => CreateMap<Ef6SourceWithoutCollection, Ef6InitializedCollectionTarget>();
}

private sealed class Ef6UninitializedCollectionProfile : MapifyProfile {
protected override void Configure() => CreateMap<Ef6SourceWithoutCollection, Ef6UninitializedCollectionTarget>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,13 @@ public void CreateMap_ShouldWorkInEf6Projection_WithNestedInvokeForSingleAndColl

db.SaveChanges();

var addressMap = Mapper.CreateMap<Ef6Address, Ef6AddressDto>();
var phoneMap = Mapper.CreateMap<Ef6Phone, Ef6PhoneDto>();
var mapify = new Mapify([
new Ef6AddressProfile(),
new Ef6PhoneProfile(),
new Ef6PersonInvokeProfile()
]);

var map = Mapper.CreateMap<Ef6Person, Ef6PersonDto>(x => new Ef6PersonDto {
FullName = x.FirstName + " " + x.LastName,
HomeAddress = addressMap.Invoke(x.HomeAddress),
Phones = x.Phones.Select(p => phoneMap.Invoke(p)).ToList()
});
var map = mapify.GetRequiredMap<Ef6Person, Ef6PersonDto>();

var result = db.People
.AsExpandable()
Expand Down Expand Up @@ -84,7 +83,8 @@ public void CreateMap_ShouldImplicitlyMapPrimitiveEnumerableCollections_InEf6Pro

db.SaveChanges();

var map = Mapper.CreateMap<Ef6PrimitiveCollectionsSource, Ef6PrimitiveCollectionsDto>();
var mapify = new Mapify([new Ef6PrimitiveCollectionsProfile()]);
var map = mapify.GetRequiredMap<Ef6PrimitiveCollectionsSource, Ef6PrimitiveCollectionsDto>();

var result = db.People
.OrderBy(x => x.Id)
Expand Down Expand Up @@ -129,7 +129,8 @@ public void CreateMap_ShouldThrowForPrimitiveArrayProjection_InEf6Projection() {

db.SaveChanges();

var map = Mapper.CreateMap<Ef6PrimitiveArrayCollectionsSource, Ef6PrimitiveArrayCollectionsDto>();
var mapify = new Mapify([new Ef6PrimitiveArrayCollectionsProfile()]);
var map = mapify.GetRequiredMap<Ef6PrimitiveArrayCollectionsSource, Ef6PrimitiveArrayCollectionsDto>();

// EF6 cannot translate source-side ToArray() inside LINQ-to-Entities projections.
Assert.Throws<NotSupportedException>(() => db.People
Expand Down Expand Up @@ -233,4 +234,22 @@ public void InstanceMapify_ShouldThrowForImplicitNestedArrayProjection_InEf6Proj
.Select(mapExpr)
.ToList());
}

private sealed class Ef6PersonInvokeProfile : MapifyProfile {
protected override void Configure() {
CreateMap<Ef6Person, Ef6PersonDto>(x => new Ef6PersonDto {
FullName = x.FirstName + " " + x.LastName,
HomeAddress = UseMap<Ef6Address, Ef6AddressDto>(x.HomeAddress),
Phones = UseMap<IEnumerable<Ef6Phone>, IEnumerable<Ef6PhoneDto>>(x.Phones).ToList()
});
}
}

private sealed class Ef6PrimitiveCollectionsProfile : MapifyProfile {
protected override void Configure() => CreateMap<Ef6PrimitiveCollectionsSource, Ef6PrimitiveCollectionsDto>();
}

private sealed class Ef6PrimitiveArrayCollectionsProfile : MapifyProfile {
protected override void Configure() => CreateMap<Ef6PrimitiveArrayCollectionsSource, Ef6PrimitiveArrayCollectionsDto>();
}
}
Loading
Loading