diff --git a/InstantAPIs/InstantAPIs.csproj b/InstantAPIs/InstantAPIs.csproj index d7ab559..fbad930 100644 --- a/InstantAPIs/InstantAPIs.csproj +++ b/InstantAPIs/InstantAPIs.csproj @@ -15,7 +15,7 @@ true true embedded - 0.2.1 + 0.2.2 diff --git a/InstantAPIs/InstantAPIsConfig.cs b/InstantAPIs/InstantAPIsConfig.cs index f7ce505..aaef7c4 100644 --- a/InstantAPIs/InstantAPIsConfig.cs +++ b/InstantAPIs/InstantAPIsConfig.cs @@ -5,6 +5,10 @@ internal class InstantAPIsConfig internal HashSet Tables { get; } = new HashSet(); + internal List PrimaryKeyMappingConventions { get; } = new List() { + "{ClassName}Id", "{ClassName}_Id", "Id" + }; + } @@ -17,7 +21,7 @@ public class InstantAPIsConfigBuilder where D : DbContext private readonly HashSet _IncludedTables = new(); private readonly List _ExcludedTables = new(); private const string DEFAULT_URI = "/api/"; - + public InstantAPIsConfigBuilder(D theContext) { this._TheContext = theContext; @@ -126,6 +130,22 @@ private void BuildTables() #endregion + #region Primary Key Mapping Conventions + + /// + /// Override the convention for determining primary keys of the entities. [Key] data annotation takes priority + /// + /// A list of conventions. You can use the string {ClassName} for the entity name. Ie: {ClassName}Id + /// Configuration builder with this configuraiton applied + public InstantAPIsConfigBuilder PrimaryKeyMappingConvention(List conventions) + { + this._Config.PrimaryKeyMappingConventions.Clear(); + this._Config.PrimaryKeyMappingConventions.AddRange(conventions); + return this; + } + + #endregion + internal InstantAPIsConfig Build() { diff --git a/InstantAPIs/MapApiExtensions.cs b/InstantAPIs/MapApiExtensions.cs index 2df9539..7a2caf2 100644 --- a/InstantAPIs/MapApiExtensions.cs +++ b/InstantAPIs/MapApiExtensions.cs @@ -24,9 +24,24 @@ internal static void Initialize(ILogger logger) Logger = logger; var theType = typeof(C); - var idProp = theType.GetProperty("id", BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance) ?? theType.GetProperties().FirstOrDefault(p => p.CustomAttributes.Any(a => a.AttributeType == typeof(KeyAttribute))); - - if (idProp != null) + var keyName = $"{theType.Name}Id"; + + // annotations will always override conventions.... + var idProp = theType.GetProperties().FirstOrDefault(p => p.CustomAttributes.Any(a => a.AttributeType == typeof(KeyAttribute))); + if (idProp == null) + { + foreach (var idName in WebApplicationExtensions.Configuration.PrimaryKeyMappingConventions) + { + if (idProp == null) + { + var propertyName = idName.Replace("{ClassName}", theType.Name); + idProp = theType.GetProperty(propertyName, + BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance); + } + } + } + + if (idProp != null) { _IdLookup.Add(theType, idProp); } diff --git a/InstantAPIs/WebApplicationExtensions.cs b/InstantAPIs/WebApplicationExtensions.cs index f52f6b6..026bab8 100644 --- a/InstantAPIs/WebApplicationExtensions.cs +++ b/InstantAPIs/WebApplicationExtensions.cs @@ -14,7 +14,7 @@ public static class WebApplicationExtensions internal const string LOGGER_CATEGORY_NAME = "InstantAPI"; - private static InstantAPIsConfig Configuration { get; set; } = new(); + internal static InstantAPIsConfig Configuration { get; set; } = new(); public static IEndpointRouteBuilder MapInstantAPIs(this IEndpointRouteBuilder app, Action> options = null) where D : DbContext { diff --git a/WorkingApi/Program.cs b/WorkingApi/Program.cs index 9452016..7686079 100644 --- a/WorkingApi/Program.cs +++ b/WorkingApi/Program.cs @@ -16,6 +16,7 @@ app.MapInstantAPIs(config => { config.IncludeTable(db => db.Contacts, ApiMethodsToGenerate.All, "addressBook"); + config.PrimaryKeyMappingConvention(new List() { "{ClassName}Id", "{ClassName}_Id", }); }); app.Run();