Skip to content

Commit 71902d1

Browse files
author
jaguzman
committed
Allowed to throw an exception when an entity attached to the repository does not have a primary key defined
1 parent 0318214 commit 71902d1

File tree

3 files changed

+43
-38
lines changed

3 files changed

+43
-38
lines changed

src/DotNetToolkit.Repository/Extensions/RepositoryConventionsExtensions.cs

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
using Queries.Strategies;
99
using System;
1010
using System.Collections.Concurrent;
11-
using System.Globalization;
1211
using System.Linq;
1312
using System.Linq.Expressions;
1413
using System.Reflection;
@@ -294,49 +293,21 @@ public static bool IsColumnIdentity([NotNull] this IRepositoryConventions source
294293
}
295294

296295
/// <summary>
297-
/// Throws an exception if the specified key type collection does not match the ones defined for the entity.
296+
/// Throws an exception if the specified entity type has an invalid primary key definition.
298297
/// </summary>
299298
/// <param name="source">The configurable conventions.</param>
300-
/// <param name="keyTypes">The key type collection to check against.</param>
301-
public static void ThrowsIfInvalidPrimaryKeyDefinition<T>([NotNull] this IRepositoryConventions source, [NotNull] params Type[] keyTypes) where T : class
299+
internal static void ThrowsIfInvalidPrimaryKeyDefinition<T>([NotNull] this IRepositoryConventions source) where T : class
302300
{
303301
EnsureOwner(source);
304-
Guard.NotEmpty(keyTypes, nameof(keyTypes));
305302

306303
var definedKeyInfos = source.GetPrimaryKeyPropertyInfos<T>();
307304

308305
if (!definedKeyInfos.Any())
309306
{
310-
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
307+
throw new InvalidOperationException(string.Format(
311308
Resources.EntityRequiresPrimaryKey,
312309
typeof(T).FullName));
313310
}
314-
315-
if (definedKeyInfos.Length > 1)
316-
{
317-
var hasNoKeyOrdering = definedKeyInfos.Any(x =>
318-
{
319-
var columnOrdering = source.GetColumnOrder(x);
320-
321-
if (!columnOrdering.HasValue)
322-
return true;
323-
324-
return columnOrdering.Value <= 0;
325-
});
326-
327-
if (hasNoKeyOrdering)
328-
{
329-
throw new InvalidOperationException(string.Format(
330-
Resources.UnableToDetermineCompositePrimaryKeyOrdering, typeof(T).FullName));
331-
}
332-
}
333-
334-
var definedKeyTypes = definedKeyInfos
335-
.Select(x => x.PropertyType)
336-
.ToArray();
337-
338-
if (keyTypes.Length != definedKeyTypes.Length || definedKeyTypes.Where((t, i) => t != keyTypes[i]).Any())
339-
throw new InvalidOperationException(Resources.EntityPrimaryKeyTypesMismatch);
340311
}
341312

342313
/// <summary>

src/DotNetToolkit.Repository/RepositoryBase.cs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3046,17 +3046,30 @@ Task<IPagedQueryResult<IEnumerable<TResult>>> Getter() =>
30463046
/// Gets the repository context.
30473047
/// </summary>
30483048
/// <returns>The repository context.</returns>
3049-
protected virtual IRepositoryContext GetContext()
3049+
protected IRepositoryContext GetContext()
30503050
{
30513051
var context = _contextFactory.Create();
30523052

3053-
Guard.EnsureNotNull(context.Conventions, "No conventions have been configured for this context.");
3053+
try
3054+
{
3055+
var conventions = Guard.EnsureNotNull(
3056+
context.Conventions,
3057+
"No conventions have been configured for this context.");
3058+
3059+
if (_options.Conventions != null)
3060+
conventions.Apply(_options.Conventions);
3061+
3062+
if (context.LoggerProvider == null && LoggerProvider != null)
3063+
context.LoggerProvider = LoggerProvider;
30543064

3055-
if (_options.Conventions != null)
3056-
context.Conventions.Apply(_options.Conventions);
3065+
conventions.ThrowsIfInvalidPrimaryKeyDefinition<TEntity>();
3066+
}
3067+
catch (Exception)
3068+
{
3069+
DisposeContext(context);
30573070

3058-
if (context.LoggerProvider == null && LoggerProvider != null)
3059-
context.LoggerProvider = LoggerProvider;
3071+
throw;
3072+
}
30603073

30613074
return context;
30623075
}

test/DotNetToolkit.Repository.Integration.Test/RepositoryTests.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using Fixtures;
55
using Queries;
66
using System;
7+
using System.Reflection;
78
using System.Threading.Tasks;
89
using Xunit;
910
using Xunit.Abstractions;
@@ -36,6 +37,13 @@ public void ThrowsIfSpecificationMissingFromQueryOptionsAsync()
3637
ForAllRepositoryFactoriesAsync(TestThrowsIfSpecificationMissingFromQueryOptionsAsync);
3738
}
3839

40+
[Fact]
41+
public void ThrowsIfEntityHasNoIdOnContextCreation()
42+
{
43+
ForAllRepositoryFactories(TestThrowsIfEntityHasNoIdOnContextCreation,
44+
ContextProviderType.AzureStorageTable);
45+
}
46+
3947
private static void TestFactoryCreate(IRepositoryFactory repoFactory)
4048
{
4149
Assert.NotNull(repoFactory.Create<Customer>());
@@ -91,5 +99,18 @@ private static async Task TestThrowsIfSpecificationMissingFromQueryOptionsAsync(
9199
ex = await Assert.ThrowsAsync<InvalidOperationException>(() => repo.DeleteAsync(emptyQueryOptions));
92100
Assert.Equal("The specified query options is missing a specification predicate.", ex.Message);
93101
}
102+
103+
private static void TestThrowsIfEntityHasNoIdOnContextCreation(IRepositoryFactory repoFactory)
104+
{
105+
var repo = repoFactory.Create<CustomerWithNoId>();
106+
107+
var method = typeof(InternalRepositoryBase<CustomerWithNoId>)
108+
.GetTypeInfo()
109+
.GetDeclaredMethod("GetContext"); // protected method
110+
111+
var ex = Assert.Throws<TargetInvocationException>(() => method.Invoke(repo, null));
112+
113+
Assert.Equal($"The instance of entity type '{typeof(CustomerWithNoId).FullName}' requires a primary key to be defined.", ex.InnerException?.Message);
114+
}
94115
}
95116
}

0 commit comments

Comments
 (0)