diff --git a/CHANGELOG.md b/CHANGELOG.md index 33b33c67f..c1a01e6c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [v1.0.0-beta07] + +Breaking Changes: +* This release contains a fundamental change in how you define your IDs + * For details see [the related issue](https://github.com/andrewlock/StronglyTypedId/issues/102), the [PR](https://github.com/andrewlock/StronglyTypedId/pull/117), or the [README](./README.md) + * The "options" enums `StronglyTypedIdBackingType`, `StronglyTypedIdConverter`, and `StronglyTypedIdImplementations` have been removed. + * Instead, you simply choose one of 4 different built-in templates, or use a custom template. + +Features +* Adds `[GeneratedCode]` attribute to generated IDs (Fixes https://github.com/andrewlock/StronglyTypedId/issues/57) +* Add support for parsing `SCOPE_IDENTITY()` and `@@IDENTITY` in MSSQL with `DapperTypeHandler` (Fixes https://github.com/andrewlock/StronglyTypedId/issues/118) +* Fix exception being thrown when deserializing nullable strongly-typed id backed by string (Fixes https://github.com/andrewlock/StronglyTypedId/issues/83) +* Allow creating multiple IDs with the same name in a project (Fixes https://github.com/andrewlock/StronglyTypedId/issues/74, [thanks @jo-goro](https://github.com/andrewlock/StronglyTypedId/pull/77)!) + ## [v1.0.0-beta06] Features diff --git a/README.md b/README.md index f3726c3d9..e0983471d 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ ![Build status](https://github.com/andrewlock/StronglyTypedId/actions/workflows/BuildAndPack.yml/badge.svg) [![NuGet](https://img.shields.io/nuget/v/StronglyTypedId.svg)](https://www.nuget.org/packages/StronglyTypedId/) -StronglyTypedId makes creating strongly-typed IDs as easy as adding an attribute! No more [accidentally passing arguments in the wrong order to methods](https://andrewlock.net/using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-1/#an-example-of-the-problem) - StronglyTypedId uses .NET 6's compile-time incremental source generators to generate [the boilerplate](https://andrewlock.net/using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-2/#a-full-example-implementation) required to use strongly-typed IDs. +StronglyTypedId makes creating strongly-typed IDs as easy as adding an attribute! No more [accidentally passing arguments in the wrong order to methods](https://andrewlock.net/using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-1/#an-example-of-the-problem) - StronglyTypedId uses .NET 6+'s compile-time incremental source generators to generate [the boilerplate](https://andrewlock.net/using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-2/#a-full-example-implementation) required to use strongly-typed IDs. Simply, [install the required package](#installing) add the `[StronglyTypedId]` attribute to a `struct` (in the `StronglyTypedIds` namespace): @@ -22,43 +22,29 @@ and the source generator magically generates the backing code when you save the > StronglyTypedId requires [the .NET Core SDK v6.0.100 or greater](https://dotnet.microsoft.com/download/dotnet/6.0). -## Changes in version 1.x -Version 0.x of this library used the helper library [CodeGeneration.Roslyn](https://github.com/AArnott/CodeGeneration.Roslyn) by [AArnott](https://github.com/AArnott), for build-time source generation. In version 1.0.0 this approach has been completely replaced in favour of source generators, as these are explicitly supported in .NET 6+. As part of this change, there were a number of additional features added and breaking changes made. +## Why do I need this library? -### Breaking Changes +I have [written a blog-post series](https://andrewlock.net/using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-1/) on strongly-typed IDs that explains the issues and rational behind this library. For a detailed view, I suggest starting there, but I provide a brief introduction here. -* `StronglyTypedIds` namespace is required. In version 0.x of the library, the `[StronglyTypedId]` attribute was in the global namespace. In version 1.x, the attribute is in the `StronglyTypedIds` namespace, so you must add `namespace StronglyTypedIds;`. -* The properties exposed by `StronglyTypedIds` have changed: there is no longer a `generateJsonConverter` property. Instead, this is infered based on the `StronglyTypedIdConverters` flags provided. -* The `String` backing typed ID will throw if you call the constructor with a `null` value +This library is designed to tackle a specific instance of [_primitive obsession_](https://lostechies.com/jimmybogard/2007/12/03/dealing-with-primitive-obsession/), whereby we use primitive objects (`Guid`/`string`/`int`/`long` etc) to represent the IDs of domain objects. The problem is that these IDs are all interchangeable - an order ID can be assigned to a product ID, despite the fact that is likely nonsensical from the domain point of view. [See here for a more concrete example](https://andrewlock.net/using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-1/#an-example-of-the-problem). -### New Features +By using strongly-typed IDs, we give each ID its own `Type` which _wraps_ the underlying primitive value. This ensures you can only use the ID where it makes sense: `ProductId`s can only be assigned to products, or you can only search for products using a `ProductId`, not an `OrderId`. -* The attributes can now auto-generate additional converter types such as EF Core `ValueConverter` and Dapper `TypeHandler`, as described in [my blog posts](https://andrewlock.net/series/using-strongly-typed-entity-ids-to-avoid-primitive-obsession/). These are optional flags on the `converters` property. -* Made interface implementations (`IEquatable` and `IComparable` currently) optional. This is to potentially support additional interfaces in future versions. -* Added a `NullableString` backing type. Due to the behaviour of `struct`s in c#, the `String` backing type ID _may_ still be null, but you can't explicitly call the constructor with a null value. In contrast, you can do this with the `NullableString` backing type. -* Added a `[StronglyTypedIdDefaults]` attribute to set default values for all `[StronglyTypedId]` attributes in your project. This is useful if you want to customise all the attributes, for example, if you want to generate additional converters by default. You can still override all the properties of a `[StronglyTypedId]` instance. +Unfortunately, taking this approach requires [a lot of boilerplate and ceremony](https://andrewlock.net/using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-2/#a-full-example-implementation) to make working with the IDs manageable. This library abstracts all that away from you, by generating the boilerplate at build-time by using a Roslyn-powered code generator. -### Bug Fixes - -* Some converters had incorrect implementations, such as in ([#24](https://github.com/andrewlock/StronglyTypedId/issues/24)). These have been addressed in version 1.x. -* Better null handling has been added for the `String` backing type, handling issues such as [#32](https://github.com/andrewlock/StronglyTypedId/issues/32). -* The code is marked as auto generated, to avoid errors such as #CS1591 as described in [#27](https://github.com/andrewlock/StronglyTypedId/issues/27) -* An error deserializing nullable StronglyTypedIds with Newtonsoft.Json [#36](https://github.com/andrewlock/StronglyTypedId/issues/36) +## Requirements -## Installing +The StronglyTypedId NuGet package is a .NET Standard 2.0 package. -To use the the [StronglyTypedId NuGet package](https://www.nuget.org/packages/StronglyTypedId), install the [StronglyTypedId](https://www.nuget.org/packages/StronglyTypedId) package into your project. Depending on which converters you implement, you may need one or more of the following additional packages +You must be using the .NET 6+ SDK (though you can compile for other target frameworks like .NET Core 2.1 and .NET Framework 4.8) -* [Newtonsoft.Json](https://www.nuget.org/packages/Newtonsoft.Json/) (optional, only required if [generating a Newtonsoft `JsonConverter`](https://andrewlock.net/using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-2/#creating-a-custom-jsonconverter)). Note that in some ASP.NET Core apps, you will likely already reference this project via transitive dependencies. -* [System.Text.Json](https://www.nuget.org/packages/System.Text.Json/) (optional, only required if [generating a System.Text `JsonConverter`](https://andrewlock.net/using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-2/#creating-a-custom-jsonconverter)). Note that in .NET Core apps, you will likely already reference this project via transitive dependencies. -* [Dapper](https://www.nuget.org/packages/Dapper/) (optional, only required if [generating a type mapper](https://andrewlock.net/using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-3/#interfacing-with-external-system-using-strongly-typed-ids)) -* [EF Core](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore) (optional, only required if [generating an EF Core ValueConverter](https://andrewlock.net/strongly-typed-ids-in-ef-core-using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-4/)) +## Installing -To install the packages, add the references to your _csproj_ file, for example by running +To use StronglyTypedIds, install the [StronglyTypedId NuGet package](https://www.nuget.org/packages/StronglyTypedId) into your _csproj_ file, for example by running ```bash -dotnet add package StronglyTypedId --version 1.0.0-beta06 +dotnet add package StronglyTypedId --version 1.0.0-beta07 ``` This adds a `` to your project. You can additionally mark the package as `PrivateAsets="all"` and `ExcludeAssets="runtime"`. @@ -75,7 +61,7 @@ This adds a `` to your project. You can additionally mark the - + @@ -93,18 +79,23 @@ using StronglyTypedIds; public partial struct FooId { } ``` -This generates the "default" strongly-typed ID using a `Guid` backing field, a custom `TypeConverter`, and a custom `JsonConverter` based on Newtonsoft.Json. +This generates the "default" strongly-typed ID using a `Guid` backing field. You can use your IDE's _Go to Definition_ functionality on your ID to see the_exact code generated by the source generator. The ID implements the following interfaces automatically: -### Customising the converters +- `IComparable` +- `IEquatable` +- `IFormattable` +- `ISpanFormattable` (.NET 6+) +- `IParsable` (.NET 7+) +- `ISpanParsable` (.NET 7+) +- `IUtf8SpanFormattable` (.NET 8+) +- `IUtf8SpanParsable` (.NET 8+) -You can customise which converters to generate by using flags. For example, to generate a `TypeConverter`, a `System.Text.JsonConverter`, and an EF Core `ValueConverter`, use +And it additionally includes two converters/serializers: -```csharp -using StronglyTypedIds; +- `System.ComponentModel.TypeConverter` +- `System.Text.Json.Serialization.JsonConverter` -[StronglyTypedId(converters: StronglyTypedIdConverter.TypeConverter | StronglyTypedIdConverter.SystemTextJson | StronglyTypedIdConverter.EfCoreValueConverter)] -public partial struct SystemTextJsonConverterId { } -``` +This provides basic integration for many use cases, but you may want to customize the IDs further, as you'll see shortly. ### Using different types as a backing fields @@ -119,49 +110,202 @@ public partial struct FooId { } var id = new FooId(Guid.NewGuid()); ``` -You can choose a different type backing field, by passing a value of the `StronglyTypedIdBackingType` enum in the constructor. +You can choose a different type backing field, by passing a value of the `Template` enum in the constructor. ```csharp using StronglyTypedIds; -[StronglyTypedId(backingType: StronglyTypedIdBackingType.String)] +[StronglyTypedId(Template.Int)] public partial struct FooId { } -var id = new FooId("my-id-value"); +var id = new FooId(123); ``` -Currently supported values are `Guid` (the default), `int`, `long`, and `string`. -## Changing the defaults globally +Currently supported built-in backing types are: + +- `Guid` (the default) +- `int` +- `long` +- `string` -If you wish to change the converters, backing types, or implementations used by default for _all_ the `[StronglyTypedId]`-decorated IDs in your project, you can use the assembly attribute `[StronglyTypedIdDefaults]` to set all of these. For example, the following sets the default converter to a whole project to `[SystemTextJson]`, and changes the default backing-type to an `int` +### Changing the defaults globally + +If you wish to change the template used by default for _all_ the `[StronglyTypedId]`-decorated IDs in your project, you can use the assembly attribute `[StronglyTypedIdDefaults]` to set all of these. For example, the following changes the default backing-type for all IDs to `int` ```csharp // Set the defaults for the project -[assembly:StronglyTypedIdDefaults( - backingType: StronglyTypedIdBackingType.Int, - converters: StronglyTypedIdConverter.SystemTextJson)] +[assembly:StronglyTypedIdDefaults(Template.Int)] -[StronglyTypedId] +[StronglyTypedId] // Uses the default 'int' template public partial struct OrderId { } -[StronglyTypedId] +[StronglyTypedId] // Uses the default 'int' template public partial struct UserId { } + +[StronglyTypedId(Template.Guid)] // Overrides the default to use 'Guid' template +public partial struct HostId { } ``` -This is equivalent to setting these values manually on all the IDs: +### Using custom templates + +In addition to the built-in templates, you can provide your _own_ templates for use with strongly typed IDs. To do this, do the following: + +- Add a file to your project with the name _TEMPLATE.typedid_, where `TEMPLATE` is the name of the template +- Update the template with your desired ID content. Use `PLACEHOLDERID` inside the template. This will be replaced with the ID's name when generating the template. +- Update the "build action" for the template to `AdditionalFiles` or `C# analyzer additional file` (depending on your IDE). + +For example, you could create a template that provides an EF Core `ValueConverter` implementation called _guid-efcore.typedid_ like this: ```csharp -[StronglyTypedId( - backingType: StronglyTypedIdBackingType.Int, - converters: StronglyTypedIdConverter.SystemTextJson)] -public partial struct OrderId { } +partial struct PLACEHOLDERID +{ + public class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter + { + public EfCoreValueConverter() : this(null) { } + public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null) + : base( + id => id.Value, + value => new PLACEHOLDERID(value), + mappingHints + ) { } + } +} +``` + +> Note that the content of the _guid-efcore.typedid_ file is valid C#. One easy way to author these templates is to create a _.cs_ file containing the code you want for your ID, then rename your ID to `PLACEHOLDERID`, change the file extension from _.cs_ to _.typedid, and then set the build action. + +After creating a template in your project you can apply it to your IDs like this: -[StronglyTypedId( - backingType: StronglyTypedIdBackingType.Int, - converters: StronglyTypedIdConverter.SystemTextJson)] -public partial struct UserId { } +```csharp +// Use the built-in Guid template and also the custom template +[StronglyTypedId(Template.Guid, "guid-efcore")] +public partial struct GuidId {} ``` +This shows another important feature: you can specify _multiple_ templates to use when generating the ID. + +### Using multiple templates + +When specifying the templates for an ID, you can specify + +- 0 or 1 built-in templates (using `Template.Guid` etc) +- 0 or more custom templates + +For example: + +```csharp +[StronglyTypedId] // Use the default templates +public partial struct MyDefaultId {} + +[StronglyTypedId(Template.Guid)] // Use a built-in template only +public partial struct MyId1 {} + +[StronglyTypedId("my-guid")] // Use a custom template only +public partial struct MyId2 {} + +[StronglyTypedId("my-guid", "guid-efcore")] // Use multiple custom templates +public partial struct MyId2 {} + +[StronglyTypedId(Template.Guid, "guid-efcore")] // Use a built-in template _and_ a custom template +public partial struct MyId3 {} + +// Use a built-in template _and_ multiple custom template +[StronglyTypedId(Template.Guid, "guid-efcore", "guid-dapper")] +public partial struct MyId4 {} +``` + +Similarly, for the optional `[StronglyTypedIdDefaults]` assembly attribute, which defines the _default_ templates to use when you use the raw `[StronglyTypedId]` attribute, you use a combination of built-in and/or custom templates: + +```csharp +//⚠ You can only use _one_ of these in your project, they're all shown here for comparison + +[assembly:StronglyTypedIdDefaults(Template.Guid)] // Use a built-in template only + +[assembly:StronglyTypedIdDefaults("my-guid")] // Use a custom template only + +[assembly:StronglyTypedIdDefaults("my-guid", "guid-efcore")] // Use multiple custom templates + +[assembly:StronglyTypedIdDefaults(Template.Guid, "guid-efcore")] // Use a built-in template _and_ a custom template + +// Use a built-in template _and_ multiple custom template +[assembly:StronglyTypedIdDefaults(Template.Guid, "guid-efcore", "guid-dapper")] + +[StronglyTypedId] // Uses whatever templates were specified! +public partial struct MyDefaultId {} +``` + +To simplify the creation of templates, the _StronglyTypedId_ package includes a code-fix provider to generate a template. + +## Creating a custom template with the Roslyn CodeFix provider + +As well as the source generator, the _StronglyTypedId_ NuGet package includes a CodeFix provider that looks for cases where you have specified a custom template that the source generator cannot find. For example, in the following code,the `"some-int"` template does not yet exist: + +```csharp +[StronglyTypedId("some-int")] // does not exist +public partial struct MyStruct { } +``` + +In the IDE, you can see the generator has marked this as an error: + +![An error is shown when the template does not exist](https://github.com/andrewlock/StronglyTypedId/assets/18755388/2a0ed4ce-0c0b-4508-b2c0-46ba7b756b8e) + +The image above also shows that there's a CodeFix action available. Clicking the action reveals the possible fix: **Add some-int.typedid template to the project**, and shows a preview of the file that will be added: + +![Showing the CodeFix in action, suggesting you can add a project](https://github.com/andrewlock/StronglyTypedId/assets/18755388/ffd62acd-3ea9-448b-adc7-5255cae651c3) + +Choosing this option will add the template to your project. + +> Unfortunately, [due to limitations with the Roslyn APIs](https://github.com/dotnet/roslyn/issues/4655), it's not possible to add the new template with the required **AdditionalFiles**/**C# analyzer additional file** build action already set. Until you change the build-action, the error will remain on your `[StronglyTypedId]` attribute. + +Right-click the newly-added template, choose **Properties**, and change the **Build Action** to either **C# analyzer additional file** (Visual Studio 2022) or **AdditionalFiles** (JetBrains Rider). The source generator will then detect your template and the error will disappear. + +The CodeFix provider does a basic check against the name of the template you're trying to create. If it includes `int`, `long`, or `string`, the template it creates will be based on one of those backing types. Otherwise, the template is based on a `Guid` backing type. + +Once the template is created, you're free to edit it as required. + +## "Community" templates package _StronglyTypedId.Templates_ + +The "template-based" design of StronglyTypedId is intended to make it easy to get started, while also giving you the flexibility to customise your IDs to your needs. + +To make it easier to share templates with multiple people, and optional _StronglyTypedId.Templates_ NuGet package is available that includes various converters and other backing types. To use these templates, add the _StronglyTypedId.Templates_ package to your project: + +```bash +dotnet add package StronglyTypedId.Templates --version 1.0.0-beta07 +``` + +You will then be able to reference any of the templates it includes. This includes "complete" implementations, including multiple converters, for various backing types: + + +- `guid-full` +- `int-full` +- `long-full` +- `string-full` +- `nullablestring-full` +- `newid-full` + + +It also includes "standalone" EF Core, Dapper, and Newtonsoft JSON converter templates to enhance the `Guid`/`int`/`long`/`string` built-in templates. For example + +- Templates for use with `Template.Guid` + - `guid-dapper` + - `guid-efcore` + - `guid-newtonsoftjson` +- Templates for use with `Template.Int` + - `int-dapper` + - `int-efcore` + - `int-newtonsoftjson` +- Templates for use with `Template.Long` + - `long-dapper` + - `long-efcore` + - `long-newtonsoftjson` +- Templates for use with `Template.String` + - `string-dapper` + - `string-efcore` + - `string-newtonsoftjson` + +For the full list of available templates, [see GitHub](https://github.com/andrewlock/StronglyTypedId/tree/master/src/StronglyTypedIds.Templates). + +You can also create your own templates package and distribute it on NuGet. ## Embedding the attributes in your project @@ -183,7 +327,7 @@ Your project file should look something like this: - @@ -208,7 +352,7 @@ If you wish to preserve these attributes in the build output, you can define the - + @@ -224,35 +368,4 @@ In previous versions of the StronglyTypedId generator, the `[StronglyTypedId]` a warning CS0436: The type 'StronglyTypedIdImplementations' in 'StronglyTypedIds\StronglyTypedIds.StronglyTypedIdGenerator\StronglyTypedIdImplementations.cs' conflicts with the imported type 'StronglyTypedIdImplementations' in 'MyProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. ``` -In the latest version of _StronglyTypedId_, the attributes are not embedded by default, so you should not experience this problem. If you see this error, compare your installation to the examples in the installation guide. - -## Why do I need this library? - -I have [written a blog-post series](https://andrewlock.net/using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-1/) on strongly-typed IDs that explains the issues and rational behind this library. For a detailed view, I suggest starting there, but I provide a brief introduction here. - -This library is designed to tackle a specific instance of [_primitive obsession_](https://lostechies.com/jimmybogard/2007/12/03/dealing-with-primitive-obsession/), whereby we use primitive objects (`Guid`/`string`/`int`/`long` etc) to represent the IDs of domain objects. The problem is that these IDs are all interchangeable - an order ID can be assigned to a product ID, despite the fact that is likely nonsensical from the domain point of view. [See here for a more concrete example](https://andrewlock.net/using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-1/#an-example-of-the-problem). - -By using strongly-typed IDs, we give each ID its own `Type` which _wraps_ the underlying primitive value. This ensures you can only use the ID where it makes sense: `ProductId`s can only be assigned to products, or you can only search for products using a `ProductId`, not an `OrderId`. - -Unfortunately, taking this approach requires [a lot of boilerplate and ceremony](https://andrewlock.net/using-strongly-typed-entity-ids-to-avoid-primitive-obsession-part-2/#a-full-example-implementation) to make working with the IDs manageable. This library abstracts all that away from you, by generating the boilerplate at build-time by using a Roslyn-powered code generator. - -## What code is generated? - -The exact code generated depends on the arguments you provide to the `StronglyTypedId` attribute. The code is generated to the _obj_ folder of the project, so you can use _Go to Definition_ on your Id to see the _exact_ code generated in each case. - -You can see see example implementations in the test `SourceGenerationHelperSnapshotTests` in which all permutations of the attribute are tested, and examples generated in [the snapshots folder](/test/StronglyTypedIds.Tests/Snapshots). - -## Requirements - -The StronglyTypedId NuGet package is a .NET Standard 2.0 package. - -You must be using the .NET 6+ SDK (though you can compile for other target frameworks like .NET Core 2.1 and .NET Framework 4.8) - -The `struct`s you decorate with the `StronglyTypedId` attribute must be marked `partial`. - -## Credits -[Credits]: #credits - -`StronglyTypedId` wouldn't work if not for [AArnott's CodeGeneration.Roslyn](https://github.com/AArnott/CodeGeneration.Roslyn) library. - -The build process and general design of the library was modelled on the [RecordGenerator](https://github.com/amis92/RecordGenerator/blob/master/README.md) project, which is similar to this project, but can be used to generate immutable Record types. +In the latest version of _StronglyTypedId_, the attributes are not embedded by default, so you should not experience this problem. If you see this error, compare your installation to the examples in the installation guide. \ No newline at end of file diff --git a/docs/migration.md b/docs/migration.md new file mode 100644 index 000000000..633200cd1 --- /dev/null +++ b/docs/migration.md @@ -0,0 +1,27 @@ +# Migration Guide + +This page describes how to migrate between specific versions in which major updates were made. + +## Migrating from 0.x.x -> 1.x.x + +Version 0.x of this library used the helper library [CodeGeneration.Roslyn](https://github.com/AArnott/CodeGeneration.Roslyn) by [AArnott](https://github.com/AArnott), for build-time source generation. In version 1.0.0 this approach has been completely replaced in favour of source generators, as these are explicitly supported in .NET 6+. As part of this change, there were a number of additional features added and breaking changes made. + +### Breaking Changes + +* `StronglyTypedIds` namespace is required. In version 0.x of the library, the `[StronglyTypedId]` attribute was in the global namespace. In version 1.x, the attribute is in the `StronglyTypedIds` namespace, so you must add `namespace StronglyTypedIds;`. +* The properties exposed by `StronglyTypedIds` have changed: there is no longer a `generateJsonConverter` property. Instead, this is infered based on the `StronglyTypedIdConverters` flags provided. +* The `String` backing typed ID will throw if you call the constructor with a `null` value + +### New Features + +* The attributes can now auto-generate additional converter types such as EF Core `ValueConverter` and Dapper `TypeHandler`, as described in [my blog posts](https://andrewlock.net/series/using-strongly-typed-entity-ids-to-avoid-primitive-obsession/). These are optional flags on the `converters` property. +* Made interface implementations (`IEquatable` and `IComparable` currently) optional. This is to potentially support additional interfaces in future versions. +* Added a `NullableString` backing type. Due to the behaviour of `struct`s in c#, the `String` backing type ID _may_ still be null, but you can't explicitly call the constructor with a null value. In contrast, you can do this with the `NullableString` backing type. +* Added a `[StronglyTypedIdDefaults]` attribute to set default values for all `[StronglyTypedId]` attributes in your project. This is useful if you want to customise all the attributes, for example, if you want to generate additional converters by default. You can still override all the properties of a `[StronglyTypedId]` instance. + +### Bug Fixes + +* Some converters had incorrect implementations, such as in ([#24](https://github.com/andrewlock/StronglyTypedId/issues/24)). These have been addressed in version 1.x. +* Better null handling has been added for the `String` backing type, handling issues such as [#32](https://github.com/andrewlock/StronglyTypedId/issues/32). +* The code is marked as auto generated, to avoid errors such as #CS1591 as described in [#27](https://github.com/andrewlock/StronglyTypedId/issues/27) +* An error deserializing nullable StronglyTypedIds with Newtonsoft.Json [#36](https://github.com/andrewlock/StronglyTypedId/issues/36) \ No newline at end of file diff --git a/releasenotes.props b/releasenotes.props index 61555da8f..a5d619e4d 100644 --- a/releasenotes.props +++ b/releasenotes.props @@ -3,7 +3,22 @@ 1.0.0 - beta06 + beta07 $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)