include IQueryable-results (#578)
This commit is contained in:
Родитель
e406283c28
Коммит
6212cd3da3
34
readme.md
34
readme.md
|
@ -75,7 +75,7 @@ builder.UseSqlServer(connection);
|
|||
builder.EnableRecording();
|
||||
var data = new SampleDbContext(builder.Options);
|
||||
```
|
||||
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L281-L288' title='Snippet source file'>snippet source</a> | <a href='#snippet-enablerecording' title='Start of snippet'>anchor</a></sup>
|
||||
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L294-L301' title='Snippet source file'>snippet source</a> | <a href='#snippet-enablerecording' title='Start of snippet'>anchor</a></sup>
|
||||
<!-- endSnippet -->
|
||||
|
||||
`EnableRecording` should only be called in the test context.
|
||||
|
@ -103,7 +103,7 @@ await data.Companies
|
|||
|
||||
await Verify(data.Companies.Count());
|
||||
```
|
||||
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L378-L395' title='Snippet source file'>snippet source</a> | <a href='#snippet-recording' title='Start of snippet'>anchor</a></sup>
|
||||
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L391-L408' title='Snippet source file'>snippet source</a> | <a href='#snippet-recording' title='Start of snippet'>anchor</a></sup>
|
||||
<!-- endSnippet -->
|
||||
|
||||
Will result in the following verified file:
|
||||
|
@ -162,7 +162,7 @@ await Verify(new
|
|||
sql = entries
|
||||
});
|
||||
```
|
||||
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L503-L526' title='Snippet source file'>snippet source</a> | <a href='#snippet-recordingspecific' title='Start of snippet'>anchor</a></sup>
|
||||
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L516-L539' title='Snippet source file'>snippet source</a> | <a href='#snippet-recordingspecific' title='Start of snippet'>anchor</a></sup>
|
||||
<!-- endSnippet -->
|
||||
|
||||
|
||||
|
@ -193,7 +193,7 @@ await data2.Companies
|
|||
|
||||
await Verify(data2.Companies.Count());
|
||||
```
|
||||
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L347-L369' title='Snippet source file'>snippet source</a> | <a href='#snippet-multidbcontexts' title='Start of snippet'>anchor</a></sup>
|
||||
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L360-L382' title='Snippet source file'>snippet source</a> | <a href='#snippet-multidbcontexts' title='Start of snippet'>anchor</a></sup>
|
||||
<!-- endSnippet -->
|
||||
|
||||
<!-- snippet: CoreTests.MultiDbContexts.verified.txt -->
|
||||
|
@ -387,7 +387,7 @@ var queryable = data.Companies
|
|||
.Where(_ => _.Content == "value");
|
||||
await Verify(queryable);
|
||||
```
|
||||
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L248-L254' title='Snippet source file'>snippet source</a> | <a href='#snippet-queryable' title='Start of snippet'>anchor</a></sup>
|
||||
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L253-L259' title='Snippet source file'>snippet source</a> | <a href='#snippet-queryable' title='Start of snippet'>anchor</a></sup>
|
||||
<!-- endSnippet -->
|
||||
|
||||
Will result in the following verified file:
|
||||
|
@ -395,14 +395,26 @@ Will result in the following verified file:
|
|||
|
||||
### EF Core
|
||||
|
||||
<!-- snippet: CoreTests.Queryable.verified.txt -->
|
||||
<a id='snippet-CoreTests.Queryable.verified.txt'></a>
|
||||
<!-- snippet: CoreTests.Queryable#00.verified.txt -->
|
||||
<a id='snippet-CoreTests.Queryable#00.verified.txt'></a>
|
||||
```txt
|
||||
[
|
||||
{
|
||||
Content: value
|
||||
}
|
||||
]
|
||||
```
|
||||
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.Queryable#00.verified.txt#L1-L5' title='Snippet source file'>snippet source</a> | <a href='#snippet-CoreTests.Queryable#00.verified.txt' title='Start of snippet'>anchor</a></sup>
|
||||
<!-- endSnippet -->
|
||||
|
||||
<!-- snippet: CoreTests.Queryable#01.verified.txt -->
|
||||
<a id='snippet-CoreTests.Queryable#01.verified.txt'></a>
|
||||
```txt
|
||||
SELECT [c].[Id], [c].[Content]
|
||||
FROM [Companies] AS [c]
|
||||
WHERE [c].[Content] = N'value'
|
||||
```
|
||||
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.Queryable.verified.txt#L1-L3' title='Snippet source file'>snippet source</a> | <a href='#snippet-CoreTests.Queryable.verified.txt' title='Start of snippet'>anchor</a></sup>
|
||||
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.Queryable#01.verified.txt#L1-L3' title='Snippet source file'>snippet source</a> | <a href='#snippet-CoreTests.Queryable#01.verified.txt' title='Start of snippet'>anchor</a></sup>
|
||||
<!-- endSnippet -->
|
||||
|
||||
|
||||
|
@ -549,7 +561,7 @@ To be able to use [WebApplicationFactory](https://docs.microsoft.com/en-us/dotne
|
|||
.Options);
|
||||
});
|
||||
```
|
||||
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L461-L472' title='Snippet source file'>snippet source</a> | <a href='#snippet-enablerecordingwithidentifier' title='Start of snippet'>anchor</a></sup>
|
||||
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L474-L485' title='Snippet source file'>snippet source</a> | <a href='#snippet-enablerecordingwithidentifier' title='Start of snippet'>anchor</a></sup>
|
||||
<!-- endSnippet -->
|
||||
|
||||
Then use the same identifier for recording:
|
||||
|
@ -565,7 +577,7 @@ var companies = await httpClient.GetFromJsonAsync<Company[]>("/companies");
|
|||
|
||||
var entries = EfRecording.FinishRecording(testName);
|
||||
```
|
||||
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L428-L438' title='Snippet source file'>snippet source</a> | <a href='#snippet-recordwithidentifier' title='Start of snippet'>anchor</a></sup>
|
||||
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L441-L451' title='Snippet source file'>snippet source</a> | <a href='#snippet-recordwithidentifier' title='Start of snippet'>anchor</a></sup>
|
||||
<!-- endSnippet -->
|
||||
|
||||
The results will not be automatically included in verified file so it will have to be verified manually:
|
||||
|
@ -579,7 +591,7 @@ await Verify(new
|
|||
sql = entries
|
||||
});
|
||||
```
|
||||
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L440-L448' title='Snippet source file'>snippet source</a> | <a href='#snippet-verifyrecordedcommandswithidentifier' title='Start of snippet'>anchor</a></sup>
|
||||
<sup><a href='/src/Verify.EntityFramework.Tests/CoreTests.cs#L453-L461' title='Snippet source file'>snippet source</a> | <a href='#snippet-verifyrecordedcommandswithidentifier' title='Start of snippet'>anchor</a></sup>
|
||||
<!-- endSnippet -->
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
SELECT [c].[Id], [c].[Content]
|
||||
{
|
||||
queryable: {
|
||||
Sql:
|
||||
SELECT [c].[Id], [c].[Content]
|
||||
FROM [Companies] AS [c]
|
||||
WHERE [c].[Content] = N'value'
|
||||
WHERE [c].[Content] = N'value',
|
||||
Result: [
|
||||
{
|
||||
Content: value
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
[
|
||||
{
|
||||
Content: value
|
||||
}
|
||||
]
|
|
@ -0,0 +1,6 @@
|
|||
[
|
||||
1,
|
||||
4,
|
||||
6,
|
||||
7
|
||||
]
|
|
@ -243,6 +243,11 @@ public class CoreTests
|
|||
public async Task Queryable()
|
||||
{
|
||||
var database = await DbContextBuilder.GetDatabase("Queryable");
|
||||
await database.AddData(
|
||||
new Company
|
||||
{
|
||||
Content = "value"
|
||||
});
|
||||
var data = database.Context;
|
||||
|
||||
#region Queryable
|
||||
|
@ -269,10 +274,18 @@ public class CoreTests
|
|||
public async Task NestedQueryable()
|
||||
{
|
||||
var database = await DbContextBuilder.GetDatabase("NestedQueryable");
|
||||
await database.AddData(
|
||||
new Company
|
||||
{
|
||||
Content = "value"
|
||||
});
|
||||
var data = database.Context;
|
||||
var queryable = data.Companies
|
||||
.Where(_ => _.Content == "value");
|
||||
await Verify(queryable);
|
||||
await Verify(new
|
||||
{
|
||||
queryable
|
||||
});
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedVariable
|
||||
|
|
|
@ -1,18 +1,53 @@
|
|||
class QueryableConverter :
|
||||
WriteOnlyJsonConverter
|
||||
{
|
||||
static MethodInfo executeQueryableDefinition;
|
||||
|
||||
static QueryableConverter() =>
|
||||
executeQueryableDefinition = typeof(QueryableConverter).GetMethod("ExecuteQueryable", BindingFlags.NonPublic| BindingFlags.Static)!;
|
||||
|
||||
public override void Write(VerifyJsonWriter writer, object data)
|
||||
{
|
||||
var sql = QueryToSql(data);
|
||||
var queryable = (IQueryable) data;
|
||||
var sql = queryable.ToQueryString();
|
||||
if(!TryExecuteQueryable(queryable, out var result))
|
||||
{
|
||||
writer.Serialize(sql);
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteStartObject();
|
||||
writer.WritePropertyName("Sql");
|
||||
writer.Serialize(sql);
|
||||
writer.WritePropertyName("Result");
|
||||
writer.Serialize(result);
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
|
||||
public static string QueryToSql(object data)
|
||||
public static bool TryExecuteQueryable(IQueryable queryable, [NotNullWhen(true)] out IList? result)
|
||||
{
|
||||
var queryable = (IQueryable)data;
|
||||
return queryable.ToQueryString();
|
||||
var entityType = queryable.GetType().GenericTypeArguments.First();
|
||||
|
||||
var executeQueryable = executeQueryableDefinition.MakeGenericMethod(entityType);
|
||||
var parameters = new object?[]
|
||||
{
|
||||
queryable
|
||||
};
|
||||
try
|
||||
{
|
||||
result = (IList) executeQueryable.Invoke(null, parameters)!;
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static List<T> ExecuteQueryable<T>(IQueryable<T> queryable) =>
|
||||
queryable.ToList();
|
||||
|
||||
public override bool CanConvert(Type type)
|
||||
=> IsQueryable(type);
|
||||
|
||||
|
|
|
@ -135,7 +135,14 @@ public static class VerifyEntityFramework
|
|||
|
||||
static ConversionResult QueryableToSql(object arg, IReadOnlyDictionary<string, object> context)
|
||||
{
|
||||
var sql = QueryableConverter.QueryToSql(arg);
|
||||
var queryable = (IQueryable) arg;
|
||||
|
||||
var sql = queryable.ToQueryString();
|
||||
if (QueryableConverter.TryExecuteQueryable(queryable, out var result))
|
||||
{
|
||||
return new(result, "txt", sql);
|
||||
}
|
||||
|
||||
return new(null, "txt", sql);
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче