Add support for identity primary keys#145
Conversation
8fdd56d to
92ba9ed
Compare
| { | ||
| public DocumentWithIdentityIdAndRowVersionMap() | ||
| { | ||
| Id(t => t.Id).Identity(); |
There was a problem hiding this comment.
This is how you define an IDENTITY primary key column
| { | ||
| SchemaGenerator.WriteTableSchema(map.Build(), null, schema); | ||
| } | ||
| schema.AppendLine($"ALTER TABLE [TestSchema].[{nameof(DocumentWithRowVersion)}] ADD [RowVersion] rowversion"); |
There was a problem hiding this comment.
Handled in SchemaGenerator now
| } | ||
|
|
||
| protected async Task<TResult[]> ReadResultsAsync<TResult>(PreparedCommand preparedCommand, Func<DbDataReader, TResult> mapper) | ||
| protected async Task<TResult[]> ReadResultsAsync<TResult>(PreparedCommand preparedCommand, Func<DbDataReader, Task<TResult>> mapper) |
There was a problem hiding this comment.
ReadResultsAsync now is an async mapper func (async all the way down)
| public string AllocateId<TDocument>() | ||
| { | ||
| var mapping = configuration.DocumentMaps.Resolve<TDocument>(); | ||
| return AllocateId(mapping); | ||
| } |
There was a problem hiding this comment.
Handy new overload (save a lot of AllocateId(typeof(MyDocument)))
| @@ -216,7 +230,7 @@ public string AllocateId(string tableName, string idPrefix) | |||
| return AllocateId(tableName, key => $"{idPrefix}-{key}"); | |||
There was a problem hiding this comment.
This overload is a problem. Ideally you shouldn't be able to Allocate an Id for an Identity column (the db is doing it for you) and it should throw an exception, however you only receive a string name, so we either have to look up the mapping (which we are already doing above) or we just have to let the code fail badly.
I would be in favour of removing the public API string AllocateId(string tableName, string idPrefix) and only allowing public API's that take something that has a DocumentMap, where we can change this.
How often are you allocating Id's for a table that you don't have a document map for... seems weird
There was a problem hiding this comment.
Octopus server does exactly this to allocate Tag Ids. They are technically a child of TagSet, but the Ids are issued as though it was a table of its own. Agreed it is an edge case usage, but it is used. Handling for the prefixes has been cleaned up in #149, which builds on top of this PR's work.
| DataModificationOutput[] ExecuteDataModification(PreparedCommand command) | ||
| { | ||
| if (!command.Mapping.IsRowVersioningEnabled) | ||
| if (!command.Mapping.HasModificationOutputs) |
There was a problem hiding this comment.
there are 2 different possible modification outputs, the RowVersion and/or the new Id
|
|
||
| namespace Nevermore.Mapping | ||
| { | ||
| public class IdColumnMapping : ColumnMapping, IIdColumnMappingBuilder |
There was a problem hiding this comment.
This is a new inherited version of ColumnMapping, specific to the Id column, allowing for specific Id column mapping
| catch (Exception ex) | ||
| { | ||
| throw new Exception($"Exception occurred while executing a reader for `{command.CommandText}`", ex); | ||
| } |
There was a problem hiding this comment.
This exception handler was bad:tm:
It was catching unique constraint exception too early in the call chain and hiding the underlying sql error. The reason this changed in this PR is that previously it only threw the exception when the reader made the 1st call to .Read(), but the exception is now thrown here because the generated SQL is different and the exception is thrown at this point, rather than when read.
| if (mapping.IdColumn.IsIdentity && options.CustomAssignedId != null) | ||
| throw new InvalidOperationException($"{nameof(InsertOptions)}.{nameof(InsertOptions.CustomAssignedId)} is not supported for identity Id columns."); |
There was a problem hiding this comment.
You obv can't set an custom assigned Id with an identity column
| [typeof(short)] = "smallint", | ||
| [typeof(int)] = "int", | ||
| [typeof(long)] = "bigint" |
There was a problem hiding this comment.
because we have to define a TABLE row version, we need the sql type that matches our Id column.
dc6bf6f to
fd85926
Compare
… consistency with the other property names
…ver uses this a lot for related documents determination
…rence types that are in use
…yKeyHandler, it only makes sense for the IStringBasedPrimitivePrimaryKeyHandler handlers
…builders, and take config in to make sure that every document map ends up with an IdColumn that has a PrimaryKeyHandler and specifies whether it is an Identity
… up how keys are handled in there
…eated to pass to the `KeyHandler` method for the IdColumn, to customise the id handling for a given document map
…ix, rather than the Func
…rection correctly
…ration code, it didn't cater for custom primary key handlers. The handlers now supply it with the information it needs.
|
This page in the Wiki should be updated after this PR merges |
Added the concept of Primary Key Handlers
This PR adds support for identity number (
short/int/long) primary keys.There is a new
Identity()method that chains off theId()method in theDocumentMap. This marks the Id column as an identity column.e.g.
Id(c => c.Id).Identity()This works by retrieving the identity value as part of the
INSERTand updating theIdon the document, very similar to how theRowVersionis updated.As there are now 2 output parameters, we need to change to use a table parameter to store them in. This also handles multiple inserts in a single statement