Skip to content

Commit 86c4d04

Browse files
committed
Fixed member comparison
1 parent 4d5eb20 commit 86c4d04

File tree

8 files changed

+244
-175
lines changed

8 files changed

+244
-175
lines changed
Lines changed: 42 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,42 @@
1-
using System.Reflection;
2-
using Microsoft.EntityFrameworkCore.Metadata;
3-
using Thinktecture.EntityFrameworkCore.Data;
4-
5-
namespace Thinktecture.EntityFrameworkCore.BulkOperations;
6-
7-
internal sealed class ExcludingEntityPropertiesProvider : IEntityPropertiesProvider
8-
{
9-
private readonly IReadOnlyList<MemberInfo> _members;
10-
11-
public ExcludingEntityPropertiesProvider(IReadOnlyList<MemberInfo> members)
12-
{
13-
_members = members ?? throw new ArgumentNullException(nameof(members));
14-
}
15-
16-
public IReadOnlyList<PropertyWithNavigations> GetPropertiesForTempTable(IEntityType entityType, bool? inlinedOwnTypes)
17-
{
18-
return Filter(IEntityPropertiesProvider.Default.GetPropertiesForTempTable(entityType, inlinedOwnTypes));
19-
}
20-
21-
private IReadOnlyList<PropertyWithNavigations> Filter(IReadOnlyList<PropertyWithNavigations> properties)
22-
{
23-
return properties.Where(p => _members.All(m => m != p.Property.PropertyInfo && m != p.Property.FieldInfo))
24-
.ToList();
25-
}
26-
27-
public IReadOnlyList<PropertyWithNavigations> GetKeyProperties(IEntityType entityType, bool? inlinedOwnTypes)
28-
{
29-
return Filter(IEntityPropertiesProvider.Default.GetKeyProperties(entityType, inlinedOwnTypes));
30-
}
31-
32-
public IReadOnlyList<PropertyWithNavigations> GetPropertiesForInsert(IEntityType entityType, bool? inlinedOwnTypes)
33-
{
34-
return Filter(IEntityPropertiesProvider.Default.GetPropertiesForInsert(entityType, inlinedOwnTypes));
35-
}
36-
37-
public IReadOnlyList<PropertyWithNavigations> GetPropertiesForUpdate(IEntityType entityType, bool? inlinedOwnTypes)
38-
{
39-
return Filter(IEntityPropertiesProvider.Default.GetPropertiesForUpdate(entityType, inlinedOwnTypes));
40-
}
41-
}
1+
using System.Reflection;
2+
using Microsoft.EntityFrameworkCore.Metadata;
3+
using Thinktecture.EntityFrameworkCore.Data;
4+
5+
namespace Thinktecture.EntityFrameworkCore.BulkOperations;
6+
7+
internal sealed class ExcludingEntityPropertiesProvider : IEntityPropertiesProvider
8+
{
9+
private readonly IReadOnlyList<MemberInfo> _members;
10+
11+
public ExcludingEntityPropertiesProvider(IReadOnlyList<MemberInfo> members)
12+
{
13+
_members = members ?? throw new ArgumentNullException(nameof(members));
14+
}
15+
16+
public IReadOnlyList<PropertyWithNavigations> GetPropertiesForTempTable(IEntityType entityType, bool? inlinedOwnTypes)
17+
{
18+
return Filter(IEntityPropertiesProvider.Default.GetPropertiesForTempTable(entityType, inlinedOwnTypes));
19+
}
20+
21+
private IReadOnlyList<PropertyWithNavigations> Filter(IReadOnlyList<PropertyWithNavigations> properties)
22+
{
23+
return properties.Where(p => _members.All(m => !m.IsEqualTo(p.Property.PropertyInfo)
24+
&& !m.IsEqualTo(p.Property.FieldInfo)))
25+
.ToList();
26+
}
27+
28+
public IReadOnlyList<PropertyWithNavigations> GetKeyProperties(IEntityType entityType, bool? inlinedOwnTypes)
29+
{
30+
return Filter(IEntityPropertiesProvider.Default.GetKeyProperties(entityType, inlinedOwnTypes));
31+
}
32+
33+
public IReadOnlyList<PropertyWithNavigations> GetPropertiesForInsert(IEntityType entityType, bool? inlinedOwnTypes)
34+
{
35+
return Filter(IEntityPropertiesProvider.Default.GetPropertiesForInsert(entityType, inlinedOwnTypes));
36+
}
37+
38+
public IReadOnlyList<PropertyWithNavigations> GetPropertiesForUpdate(IEntityType entityType, bool? inlinedOwnTypes)
39+
{
40+
return Filter(IEntityPropertiesProvider.Default.GetPropertiesForUpdate(entityType, inlinedOwnTypes));
41+
}
42+
}

src/Thinktecture.EntityFrameworkCore.BulkOperations/Extensions/BulkOperationsCollectionExtensions.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ internal static IReadOnlyList<PropertyWithNavigations> ConvertToEntityProperties
4646

4747
private static IProperty? FindProperty(IEntityType entityType, MemberInfo memberInfo)
4848
{
49-
return entityType.GetProperties().FirstOrDefault(property => property.PropertyInfo?.MetadataToken == memberInfo.MetadataToken
50-
|| property.FieldInfo?.MetadataToken == memberInfo.MetadataToken);
49+
return entityType.GetProperties().FirstOrDefault(property => memberInfo.IsEqualTo(property.PropertyInfo)
50+
|| memberInfo.IsEqualTo(property.FieldInfo));
5151
}
5252

5353
private static INavigation? FindOwnedProperty(
@@ -56,7 +56,7 @@ internal static IReadOnlyList<PropertyWithNavigations> ConvertToEntityProperties
5656
{
5757
foreach (var ownedTypeNavi in entityType.GetOwnedTypesProperties(null)) // search for all owned properties, i.e., don't use "inlinedOwnTypes" from the caller
5858
{
59-
if (ownedTypeNavi.PropertyInfo == memberInfo || ownedTypeNavi.FieldInfo == memberInfo)
59+
if (memberInfo.IsEqualTo(ownedTypeNavi.PropertyInfo) || memberInfo.IsEqualTo(ownedTypeNavi.FieldInfo))
6060
{
6161
if (ownedTypeNavi.IsInlined())
6262
return ownedTypeNavi;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System.Reflection;
2+
using System.Runtime.CompilerServices;
3+
4+
namespace Thinktecture;
5+
6+
internal static class MemberInfoExtensions
7+
{
8+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
9+
public static bool IsEqualTo(this MemberInfo member, MemberInfo? other)
10+
{
11+
return other is not null
12+
&& member.MetadataToken == other.MetadataToken
13+
&& ReferenceEquals(member.Module, other.Module);
14+
}
15+
}
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,81 @@
1-
using Microsoft.EntityFrameworkCore.Metadata;
2-
using Thinktecture.EntityFrameworkCore.Data;
3-
using Thinktecture.TestDatabaseContext;
4-
5-
namespace Thinktecture.EntityFrameworkCore.BulkOperations.PropertiesProviderTests;
6-
7-
public class Exclude
8-
{
9-
[Fact]
10-
public void Should_throw_if_expression_is_null()
11-
{
12-
Action action = () => IEntityPropertiesProvider.Exclude<TestEntity>(null!);
13-
action.Should().Throw<ArgumentNullException>();
14-
}
15-
16-
[Fact]
17-
public void Should_throw_if_expression_return_constant()
18-
{
19-
Action action = () => IEntityPropertiesProvider.Exclude<TestEntity>(entity => null!);
20-
action.Should().Throw<NotSupportedException>();
21-
}
22-
23-
[Fact]
24-
public void Should_return_all_properties_if_no_properties_provided()
25-
{
26-
var entityType = GetEntityType<TestEntity>();
27-
var propertiesProvider = IEntityPropertiesProvider.Exclude<TestEntity>(entity => new { });
28-
var properties = propertiesProvider.GetPropertiesForTempTable(entityType, null);
29-
30-
properties.Should().HaveCount(entityType.GetProperties().Count());
31-
}
32-
33-
[Fact]
34-
public void Should_extract_all_properties_besides_the_one_specified_by_property_accessor()
35-
{
36-
var entityType = GetEntityType<TestEntity>();
37-
var idProperty = new PropertyWithNavigations(entityType.FindProperty(nameof(TestEntity.Id))!, Array.Empty<INavigation>());
38-
39-
var propertiesProvider = IEntityPropertiesProvider.Exclude<TestEntity>(entity => entity.Id);
40-
41-
var properties = propertiesProvider.GetPropertiesForTempTable(entityType, null);
42-
properties.Should().HaveCount(entityType.GetProperties().Count() - 1);
43-
properties.Should().NotContain(idProperty);
44-
}
45-
46-
[Fact]
47-
public void Should_extract_all_properties_besides_the_ones_specified_by_expression()
48-
{
49-
var entityType = GetEntityType<TestEntity>();
50-
var idProperty = new PropertyWithNavigations(entityType.FindProperty(nameof(TestEntity.Id))!, Array.Empty<INavigation>());
51-
var countProperty = new PropertyWithNavigations(entityType.FindProperty(nameof(TestEntity.Count))!, Array.Empty<INavigation>());
52-
53-
var propertiesProvider = IEntityPropertiesProvider.Exclude<TestEntity>(entity => new { entity.Id, entity.Count });
54-
55-
var properties = propertiesProvider.GetPropertiesForTempTable(entityType, null);
56-
properties.Should().HaveCount(entityType.GetProperties().Count() - 2);
57-
properties.Should().NotContain(idProperty);
58-
properties.Should().NotContain(countProperty);
59-
}
60-
61-
private static IEntityType GetEntityType<T>()
62-
{
63-
var options = new DbContextOptionsBuilder<TestDbContext>().UseSqlite("DataSource=:memory:").Options;
64-
return new TestDbContext(options).Model.GetEntityType(typeof(T));
65-
}
66-
}
1+
using Microsoft.EntityFrameworkCore.Metadata;
2+
using Thinktecture.EntityFrameworkCore.Data;
3+
using Thinktecture.TestDatabaseContext;
4+
5+
namespace Thinktecture.EntityFrameworkCore.BulkOperations.PropertiesProviderTests;
6+
7+
public class Exclude
8+
{
9+
[Fact]
10+
public void Should_throw_if_expression_is_null()
11+
{
12+
Action action = () => IEntityPropertiesProvider.Exclude<TestEntity>(null!);
13+
action.Should().Throw<ArgumentNullException>();
14+
}
15+
16+
[Fact]
17+
public void Should_throw_if_expression_return_constant()
18+
{
19+
Action action = () => IEntityPropertiesProvider.Exclude<TestEntity>(entity => null!);
20+
action.Should().Throw<NotSupportedException>();
21+
}
22+
23+
[Fact]
24+
public void Should_return_all_properties_if_no_properties_provided()
25+
{
26+
var entityType = GetEntityType<TestEntity>();
27+
var propertiesProvider = IEntityPropertiesProvider.Exclude<TestEntity>(entity => new { });
28+
var properties = propertiesProvider.GetPropertiesForTempTable(entityType, null);
29+
30+
properties.Should().HaveCount(entityType.GetProperties().Count());
31+
}
32+
33+
[Fact]
34+
public void Should_extract_all_properties_besides_the_one_specified_by_property_accessor()
35+
{
36+
var entityType = GetEntityType<TestEntity>();
37+
var idProperty = new PropertyWithNavigations(entityType.FindProperty(nameof(TestEntity.Id))!, Array.Empty<INavigation>());
38+
39+
var propertiesProvider = IEntityPropertiesProvider.Exclude<TestEntity>(entity => entity.Id);
40+
41+
var properties = propertiesProvider.GetPropertiesForTempTable(entityType, null);
42+
properties.Should().HaveCount(entityType.GetProperties().Count() - 1);
43+
properties.Should().NotContain(idProperty);
44+
}
45+
46+
[Fact]
47+
public void Should_extract_all_properties_besides_the_ones_specified_by_expression()
48+
{
49+
var entityType = GetEntityType<TestEntity>();
50+
var idProperty = new PropertyWithNavigations(entityType.FindProperty(nameof(TestEntity.Id))!, Array.Empty<INavigation>());
51+
var countProperty = new PropertyWithNavigations(entityType.FindProperty(nameof(TestEntity.Count))!, Array.Empty<INavigation>());
52+
53+
var propertiesProvider = IEntityPropertiesProvider.Exclude<TestEntity>(entity => new { entity.Id, entity.Count });
54+
55+
var properties = propertiesProvider.GetPropertiesForTempTable(entityType, null);
56+
properties.Should().HaveCount(entityType.GetProperties().Count() - 2);
57+
properties.Should().NotContain(idProperty);
58+
properties.Should().NotContain(countProperty);
59+
}
60+
61+
[Fact]
62+
public void Should_handle_properties_from_base_classes()
63+
{
64+
var entityType = GetEntityType<TestEntityWithBaseClass>();
65+
var idProperty = new PropertyWithNavigations(entityType.FindProperty(nameof(TestEntityWithBaseClass.Id))!, Array.Empty<INavigation>());
66+
var baseProperty = new PropertyWithNavigations(entityType.FindProperty(nameof(TestEntityWithBaseClass.Base_A))!, Array.Empty<INavigation>());
67+
68+
var propertiesProvider = IEntityPropertiesProvider.Exclude<TestEntityWithBaseClass>(entity => new { entity.Id, entity.Base_A });
69+
70+
var properties = propertiesProvider.GetPropertiesForTempTable(entityType, null);
71+
properties.Should().HaveCount(entityType.GetProperties().Count() - 2);
72+
properties.Should().NotContain(idProperty);
73+
properties.Should().NotContain(baseProperty);
74+
}
75+
76+
private static IEntityType GetEntityType<T>()
77+
{
78+
var options = new DbContextOptionsBuilder<TestDbContext>().UseSqlite("DataSource=:memory:").Options;
79+
return new TestDbContext(options).Model.GetEntityType(typeof(T));
80+
}
81+
}

0 commit comments

Comments
 (0)