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
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,17 @@ public static Expression CreateMemberInit(this QueryableProjectionScope scope)
private static bool ShouldReuseExistingInstance(Type type)
=> type.GetConstructor(Type.EmptyTypes) is not null
&& type.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)
.Any(t => t.GetParameters().Length > 0);
.Any(t =>
t.GetParameters().Length > 0
&& !IsRecordCopyConstructor(t, type));

private static bool IsRecordCopyConstructor(ConstructorInfo constructor, Type declaringType)
{
var parameters = constructor.GetParameters();

return parameters.Length == 1
&& parameters[0].ParameterType == declaringType;
}

public static Expression CreateMemberInitLambda(this QueryableProjectionScope scope)
=> Expression.Lambda(scope.CreateMemberInit(), scope.Parameter);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,58 @@ static Dictionary<string, int> ReadCounts(JsonElement value)
}
}

[Fact]
public async Task UseProjection_Should_Project_Only_Selected_Columns_When_Entity_Is_Record()
{
// arrange
var fileName = Guid.NewGuid().ToString("N") + ".db";
var connectionString = "Data Source=" + fileName;
var sql = new List<string>();

try
{
await using (var seed = new RecordProjectionDbContext(
new DbContextOptionsBuilder<RecordProjectionDbContext>()
.UseSqlite(connectionString)
.Options))
{
await seed.Database.EnsureCreatedAsync(Xunit.TestContext.Current.CancellationToken);
seed.Products.Add(
new RecordProjectionProduct { Id = 1, Name = "Product", Description = "Description" });
await seed.SaveChangesAsync(Xunit.TestContext.Current.CancellationToken);
}

var executor = await new ServiceCollection()
.AddDbContext<RecordProjectionDbContext>(
b => b
.UseSqlite(connectionString)
.AddInterceptors(new SqlCapturingInterceptor(sql)))
.AddGraphQL()
.AddProjections()
.AddQueryType<RecordProjectionQuery>()
.BuildRequestExecutorAsync(cancellationToken: Xunit.TestContext.Current.CancellationToken);

// act
var result = await executor.ExecuteAsync(
"{ products { id } }",
Xunit.TestContext.Current.CancellationToken);

// assert
var operationResult = result.ExpectOperationResult();
Assert.Empty(operationResult.Errors);
string.Join("\n", sql).MatchInlineSnapshot(
"""
SELECT "p"."Id"
FROM "Products" AS "p"
""");
Comment thread
glen-84 marked this conversation as resolved.
}
finally
{
Microsoft.Data.Sqlite.SqliteConnection.ClearAllPools();
File.Delete(fileName);
}
}

public class ConstructorInjectionQuery
{
[UseProjection]
Expand Down Expand Up @@ -806,6 +858,29 @@ public class ConstructorInjectionPost
public int BlogId { get; set; }
}

public class RecordProjectionQuery
{
[UseProjection]
public IQueryable<RecordProjectionProduct> GetProducts(RecordProjectionDbContext context)
=> context.Products;
}

public class RecordProjectionDbContext(
DbContextOptions<RecordProjectionDbContext> options)
: DbContext(options)
{
public DbSet<RecordProjectionProduct> Products => Set<RecordProjectionProduct>();
}

public record RecordProjectionProduct
{
public required int Id { get; init; }

public required string Name { get; init; }

public required string Description { get; init; }
}

public class SingleOrDefaultUser
{
public string Name { get; set; } = string.Empty;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ Result:

SQL:
---------------
SELECT "d"."Bar_Baz"
SELECT "d"."Bar_Baz" AS "Baz"
FROM "Data" AS "d"
---------------
Loading