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
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Project>
<PropertyGroup>
<NoWarn>CS1591;CA1416;CS8632</NoWarn>
<Version>14.4.0</Version>
<Version>14.5.0</Version>
<AssemblyVersion>1.0.0</AssemblyVersion>
<ContinuousIntegrationBuild>false</ContinuousIntegrationBuild>
</PropertyGroup>
Expand Down
4 changes: 3 additions & 1 deletion src/EfLocalDb.Tests/Contexts/TestDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,7 @@ public TestDbContext(DbContextOptions options) :
{
}

protected override void OnModelCreating(ModelBuilder model) => model.Entity<TestEntity>();
protected override void OnModelCreating(ModelBuilder model) =>
model.Entity<TestEntity>()
.HasQueryFilter(_ => _.Property != "filtered");
}
1 change: 1 addition & 0 deletions src/EfLocalDb.Tests/Tests.AnyIgnoreFilters.verified.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
True
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
False
4 changes: 4 additions & 0 deletions src/EfLocalDb.Tests/Tests.FindIgnoreFilters.verified.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
Id: 1,
Property: filtered
}
2 changes: 1 addition & 1 deletion src/EfLocalDb.Tests/Tests.FindIncorrectType.verified.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
Type: Exception,
Message: No record found with keys: key,
StackTrace: at EfLocalDb.SqlDatabase`1.Find(Object[] keys)
StackTrace: at EfLocalDb.SqlDatabase`1.InnerFind(Boolean ignoreFilters, Object[] keys)
}
10 changes: 3 additions & 7 deletions src/EfLocalDb.Tests/Tests.FindIncorrectTypeT.verified.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
{
Type: ArgumentException,
Message: The key value at position 0 of the call to 'DbSet<TestEntity>.Find' was of type 'string', which does not match the property type of 'int'.,
StackTrace:
at Microsoft.EntityFrameworkCore.Internal.EntityFinder`1.FindTracked(IKey key, Object[] keyValues)
at Microsoft.EntityFrameworkCore.Internal.EntityFinder`1.FindAsync(Object[] keyValues, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.FindAsync(Object[] keyValues)
at EfLocalDb.SqlDatabase`1.Find[T](Object[] keys)
Type: Exception,
Message: Key types dont match,
StackTrace: at EfLocalDb.SqlDatabase`1.InnerFind[T](Object[] keys, Boolean ignoreFilters)
}
2 changes: 1 addition & 1 deletion src/EfLocalDb.Tests/Tests.FindMissing.verified.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
Type: Exception,
Message: No record found with keys: 0,
StackTrace: at EfLocalDb.SqlDatabase`1.Find(Object[] keys)
StackTrace: at EfLocalDb.SqlDatabase`1.InnerFind(Boolean ignoreFilters, Object[] keys)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
Type: Exception,
Message: No record found with keys: 0,
StackTrace: at EfLocalDb.SqlDatabase`1.InnerFind(Boolean ignoreFilters, Object[] keys)
}
2 changes: 1 addition & 1 deletion src/EfLocalDb.Tests/Tests.FindMissingT.verified.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
Type: Exception,
Message: No record found with keys: 0,
StackTrace: at EfLocalDb.SqlDatabase`1.Find[T](Object[] keys)
StackTrace: at EfLocalDb.SqlDatabase`1.InnerFind[T](Object[] keys, Boolean ignoreFilters)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
Type: Exception,
Message: No record found with keys: 0,
StackTrace: at EfLocalDb.SqlDatabase`1.InnerFind[T](Object[] keys, Boolean ignoreFilters)
}
4 changes: 4 additions & 0 deletions src/EfLocalDb.Tests/Tests.FindTIgnoreFilters.verified.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
Id: 1,
Property: filtered
}
4 changes: 4 additions & 0 deletions src/EfLocalDb.Tests/Tests.SingleIgnoreFilters.verified.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
Id: 1,
Property: filtered
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
Type: InvalidOperationException,
Message: Sequence contains no elements.,
StackTrace:
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken)
}
128 changes: 122 additions & 6 deletions src/EfLocalDb.Tests/Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ public async Task SeedData()
{
Property = "prop"
};
await using var database = await instance.Build(new List<object>
{
entity
});
await using var database = await instance.Build(
new List<object>
{
entity
});
Assert.True(await database.Exists(entity.Id));
Assert.True(callbackCalled);
}
Expand All @@ -34,8 +35,8 @@ void Add(List<object?> objects, IServiceProvider provider)

await using var database = await instance.Build();
await using var asyncScope = database.CreateAsyncScope();
await using var providerAsyncScope = ((IServiceProvider)database).CreateAsyncScope();
await using var scopeFactoryAsyncScope = ((IServiceScopeFactory)database).CreateAsyncScope();
await using var providerAsyncScope = ((IServiceProvider) database).CreateAsyncScope();
await using var scopeFactoryAsyncScope = ((IServiceScopeFactory) database).CreateAsyncScope();
using var scope = database.CreateScope();
var list = new List<object?>();
Add(list, database);
Expand All @@ -54,6 +55,7 @@ void Add(List<object?> objects, IServiceProvider provider)
{
continue;
}

var nested = list[innerIndex];
Assert.NotSame(item, nested);
}
Expand Down Expand Up @@ -134,13 +136,32 @@ public async Task ExistsT()
Assert.True(await database.Exists<TestEntity>(entity.Id));
}

[Fact]
public async Task ExistsTIgnoreFilters()
{
var entity = new TestEntity
{
Property = "filtered"
};
await using var database = await instance.Build();
await database.AddDataUntracked(entity);
Assert.True(await database.ExistsIgnoreFilters<TestEntity>(entity.Id));
}

[Fact]
public async Task ExistsMissingT()
{
await using var database = await instance.Build();
Assert.False(await database.Exists<TestEntity>(0));
}

[Fact]
public async Task ExistsMissingTIgnoreFilters()
{
await using var database = await instance.Build();
Assert.False(await database.ExistsIgnoreFilters<TestEntity>(0));
}

[Fact]
public async Task FindT()
{
Expand All @@ -153,13 +174,32 @@ public async Task FindT()
await Verify(database.Find<TestEntity>(entity.Id));
}

[Fact]
public async Task FindTIgnoreFilters()
{
var entity = new TestEntity
{
Property = "filtered"
};
await using var database = await instance.Build();
await database.AddDataUntracked(entity);
await Verify(database.FindIgnoreFilters<TestEntity>(entity.Id));
}

[Fact]
public async Task FindMissingT()
{
await using var database = await instance.Build();
await ThrowsTask(() => database.Find<TestEntity>(0));
}

[Fact]
public async Task FindMissingTIgnoreFilters()
{
await using var database = await instance.Build();
await ThrowsTask(() => database.FindIgnoreFilters<TestEntity>(0));
}

[Fact]
public async Task Single()
{
Expand All @@ -172,13 +212,32 @@ public async Task Single()
await Verify(database.Single<TestEntity>(_ => _.Id == entity.Id));
}

[Fact]
public async Task SingleIgnoreFilters()
{
var entity = new TestEntity
{
Property = "filtered"
};
await using var database = await instance.Build();
await database.AddDataUntracked(entity);
await Verify(database.SingleIgnoreFilters<TestEntity>(_ => _.Id == entity.Id));
}

[Fact]
public async Task SingleMissing()
{
await using var database = await instance.Build();
await ThrowsTask(() => database.Single<TestEntity>(entity => entity.Id == 10));
}

[Fact]
public async Task SingleMissingIgnoreFilters()
{
await using var database = await instance.Build();
await ThrowsTask(() => database.SingleIgnoreFilters<TestEntity>(entity => entity.Id == 10));
}

[Fact]
public async Task Any()
{
Expand All @@ -191,13 +250,32 @@ public async Task Any()
await Verify(database.Any<TestEntity>(_ => _.Id == entity.Id));
}

[Fact]
public async Task AnyIgnoreFilters()
{
var entity = new TestEntity
{
Property = "filtered"
};
await using var database = await instance.Build();
await database.AddDataUntracked(entity);
await Verify(database.AnyIgnoreFilters<TestEntity>(_ => _.Id == entity.Id));
}

[Fact]
public async Task AnyMissing()
{
await using var database = await instance.Build();
await Verify(database.Any<TestEntity>(entity => entity.Id == 10));
}

[Fact]
public async Task AnyMissingIgnoreFilters()
{
await using var database = await instance.Build();
await Verify(database.AnyIgnoreFilters<TestEntity>(entity => entity.Id == 10));
}

[Fact]
public async Task CountT()
{
Expand All @@ -224,6 +302,18 @@ public async Task FindIncorrectTypeT()
await ThrowsTask(() => database.Find<TestEntity>("key"));
}

[Fact]
public async Task ExistsIgnoreFilter()
{
var entity = new TestEntity
{
Property = "filtered"
};
await using var database = await instance.Build();
await database.AddDataUntracked(entity);
Assert.True(await database.ExistsIgnoreFilter(entity.Id));
}

[Fact]
public async Task Exists()
{
Expand All @@ -236,6 +326,13 @@ public async Task Exists()
Assert.True(await database.Exists(entity.Id));
}

[Fact]
public async Task ExistsMissingIgnoreFilter()
{
await using var database = await instance.Build();
Assert.False(await database.ExistsIgnoreFilter(0));
}

[Fact]
public async Task ExistsMissing()
{
Expand Down Expand Up @@ -269,6 +366,25 @@ public async Task FindMissing()
await ThrowsTask(() => database.Find(0));
}

[Fact]
public async Task FindIgnoreFilters()
{
var entity = new TestEntity
{
Property = "filtered"
};
await using var database = await instance.Build();
await database.AddDataUntracked(entity);
await Verify(database.FindIgnoreFilters(entity.Id));
}

[Fact]
public async Task FindMissingIgnoreFilters()
{
await using var database = await instance.Build();
await ThrowsTask(() => database.FindIgnoreFilters(0));
}

[Fact]
public async Task FindIncorrectType()
{
Expand Down
19 changes: 19 additions & 0 deletions src/EfLocalDb/SqlDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ internal SqlDatabase(
this.sqlOptionsBuilder = sqlOptionsBuilder;
ConnectionString = connectionString;
Connection = new(connectionString);
findResult = GetType().GetMethod("FindResult", BindingFlags.Instance | BindingFlags.NonPublic)!;
dataConnection = new(() =>
{
var connection = new DataSqlConnection(connectionString);
Expand All @@ -36,6 +37,7 @@ internal SqlDatabase(
public string Name { get; }
public SqlConnection Connection { get; }
Lazy<DataSqlConnection> dataConnection;
MethodInfo findResult;
public DataSqlConnection DataConnection => dataConnection.Value;
public string ConnectionString { get; }

Expand Down Expand Up @@ -68,12 +70,29 @@ public async Task Start()
Context = NewDbContext();
NoTrackingContext = NewDbContext(QueryTrackingBehavior.NoTracking);
EntityTypes = Context.Model.GetEntityTypes().ToList();
entityKeyMap = new();
foreach (var entity in EntityTypes)
{
var key = entity.FindPrimaryKey();
if (key is null)
{
continue;
}

var find = findResult.MakeGenericMethod(entity.ClrType);
var keyTypes = key.Properties.Select(_ => _.ClrType).ToList();
entityKeyMap.Add(new(entity, keyTypes, key, find));
}
if (data is not null)
{
await AddData(data);
}
}

record EntityKeyMap(IEntityType Entity, List<Type> KeyTypes, IKey Key, MethodInfo Find);

List<EntityKeyMap> entityKeyMap = null!;

public TDbContext Context { get; private set; } = null!;
public TDbContext NoTrackingContext { get; private set; } = null!;

Expand Down
15 changes: 12 additions & 3 deletions src/EfLocalDb/SqlDatabase_Any.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,19 @@ public partial class SqlDatabase<TDbContext>
/// <typeparamref name="T" />.
/// </summary>
public Task<bool> Any<T>(Expression<Func<T, bool>>? predicate = null)
where T : class
{
var set = Set<T>();
where T : class =>
AnyAsync(Set<T>(), predicate);

/// <summary>
/// Calls <see cref="DbSet{TEntity}.FindAsync(object[])" /> on the <see cref="DbContext.Set{TEntity}()" /> for
/// <typeparamref name="T" />.
/// </summary>
public Task<bool> AnyIgnoreFilters<T>(Expression<Func<T, bool>>? predicate = null)
where T : class =>
AnyAsync(Set<T>().IgnoreQueryFilters(), predicate);

static Task<bool> AnyAsync<T>(IQueryable<T> set, Expression<Func<T, bool>>? predicate) where T : class
{
if (predicate is null)
{
return set.AnyAsync();
Expand Down
Loading