Skip to content

Commit

Permalink
Add check to single ID Project when the entity contains more than one…
Browse files Browse the repository at this point in the history
… key property


Also reordered the newly introduced Project integration test to match the Get ordering
  • Loading branch information
yankarinRG authored Oct 11, 2024
1 parent 360553d commit e3ebc63
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 38 deletions.
9 changes: 7 additions & 2 deletions src/Dommel/Project.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,13 @@ internal static string BuildProjectById(ISqlBuilder sqlBuilder, Type type, objec
var cacheKey = new QueryCacheKey(QueryCacheType.Project, sqlBuilder, type);
if (!QueryCache.TryGetValue(cacheKey, out var sql))
{
var keyProperty = Resolvers.KeyProperties(type).Single().Property;
var keyColumnName = Resolvers.Column(keyProperty, sqlBuilder);
var keyProperties = Resolvers.KeyProperties(type);
if (keyProperties.Length > 1)
{
throw new InvalidOperationException($"Entity {type.Name} contains more than one key property." +
"Use the Project<T> overload which supports passing multiple IDs.");
}
var keyColumnName = Resolvers.Column(keyProperties[0].Property, sqlBuilder);

sql = BuildProjectAllQuery(sqlBuilder, type);
sql += $" where {keyColumnName} = @Id";
Expand Down
90 changes: 54 additions & 36 deletions test/Dommel.IntegrationTests/ProjectTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,24 @@ public void Project(DatabaseDriver database)

[Theory]
[ClassData(typeof(DatabaseTestData))]
public void Project_ParamsOverload(DatabaseDriver database)
public async Task ProjectAsync(DatabaseDriver database)
{
using var con = database.GetConnection();
var p = con.Project<ProductSmall>(new object[] { 1 });
var p = await con.ProjectAsync<ProductSmall>(1);
Assert.NotNull(p);
Assert.Equal(1, p!.ProductId);
Assert.False(string.IsNullOrEmpty(p.Name));
Assert.NotEqual(0, p!.ProductId);
Assert.NotNull(p.Name);
}

[Theory]
[ClassData(typeof(DatabaseTestData))]
public async Task ProjectAsync(DatabaseDriver database)
public void Project_ParamsOverload(DatabaseDriver database)
{
using var con = database.GetConnection();
var p = await con.ProjectAsync<ProductSmall>(1);
var p = con.Project<ProductSmall>(new object[] { 1 });
Assert.NotNull(p);
Assert.NotEqual(0, p!.ProductId);
Assert.NotNull(p.Name);
Assert.Equal(1, p!.ProductId);
Assert.False(string.IsNullOrEmpty(p.Name));
}

[Theory]
Expand All @@ -55,16 +55,20 @@ public async Task ProjectAsync_ParamsOverload(DatabaseDriver database)

[Theory]
[ClassData(typeof(DatabaseTestData))]
public void ProjectAll(DatabaseDriver database)
public void Project_ThrowsWhenCompositeKey(DatabaseDriver database)
{
using var con = database.GetConnection();
var ps = con.ProjectAll<ProductSmall>();
Assert.NotEmpty(ps);
Assert.All(ps, p =>
{
Assert.NotEqual(0, p.ProductId);
Assert.NotNull(p.Name);
});
var ex = Assert.Throws<InvalidOperationException>(() => con.Project<ProjectedProductsCategories>(1));
Assert.Equal("Entity ProjectedProductsCategories contains more than one key property.Use the Project<T> overload which supports passing multiple IDs.", ex.Message);
}

[Theory]
[ClassData(typeof(DatabaseTestData))]
public async Task ProjectAsync_ThrowsWhenCompositeKey(DatabaseDriver database)
{
using var con = database.GetConnection();
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => con.ProjectAsync<ProjectedProductsCategories>(1));
Assert.Equal("Entity ProjectedProductsCategories contains more than one key property.Use the Project<T> overload which supports passing multiple IDs.", ex.Message);
}

[Theory]
Expand All @@ -89,6 +93,40 @@ public async Task ProjectAsync_CompositeKey(DatabaseDriver database)
Assert.Equal(1, p.CategoryId);
}

[Theory]
[ClassData(typeof(DatabaseTestData))]
public void Project_ThrowsWhenCompositeKeyArgumentsDontMatch(DatabaseDriver database)
{
DommelMapper.QueryCache.Clear();
using var con = database.GetConnection();
var ex = Assert.Throws<InvalidOperationException>(() => con.Project<ProjectedProductsCategories>(1, 2, 3));
Assert.Equal("Number of key columns (2) of type ProjectedProductsCategories does not match with the number of specified IDs (3).", ex.Message);
}

[Theory]
[ClassData(typeof(DatabaseTestData))]
public async Task ProjectAsync_ThrowsWhenCompositeKeyArgumentsDontMatch(DatabaseDriver database)
{
DommelMapper.QueryCache.Clear();
using var con = database.GetConnection();
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => con.ProjectAsync<ProjectedProductsCategories>(1, 2, 3));
Assert.Equal("Number of key columns (2) of type ProjectedProductsCategories does not match with the number of specified IDs (3).", ex.Message);
}

[Theory]
[ClassData(typeof(DatabaseTestData))]
public void ProjectAll(DatabaseDriver database)
{
using var con = database.GetConnection();
var ps = con.ProjectAll<ProductSmall>();
Assert.NotEmpty(ps);
Assert.All(ps, p =>
{
Assert.NotEqual(0, p.ProductId);
Assert.NotNull(p.Name);
});
}

[Theory]
[ClassData(typeof(DatabaseTestData))]
public async Task ProjectAllAsync(DatabaseDriver database)
Expand Down Expand Up @@ -130,26 +168,6 @@ public async Task ProjectPagedAsync(DatabaseDriver database)
});
}

[Theory]
[ClassData(typeof(DatabaseTestData))]
public void Project_ThrowsWhenCompositeKeyArgumentsDontMatch(DatabaseDriver database)
{
DommelMapper.QueryCache.Clear();
using var con = database.GetConnection();
var ex = Assert.Throws<InvalidOperationException>(() => con.Project<ProjectedProductsCategories>(1, 2, 3));
Assert.Equal("Number of key columns (2) of type ProjectedProductsCategories does not match with the number of specified IDs (3).", ex.Message);
}

[Theory]
[ClassData(typeof(DatabaseTestData))]
public async Task ProjectAsync_ThrowsWhenCompositeKeyArgumentsDontMatch(DatabaseDriver database)
{
DommelMapper.QueryCache.Clear();
using var con = database.GetConnection();
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => con.ProjectAsync<ProjectedProductsCategories>(1, 2, 3));
Assert.Equal("Number of key columns (2) of type ProjectedProductsCategories does not match with the number of specified IDs (3).", ex.Message);
}

// Subset of the default Product entity
[Table("Products")]
public class ProductSmall
Expand Down

0 comments on commit e3ebc63

Please sign in to comment.