Self study: DDD, .net core, entity framework core
In the Product Catalog bounded context, I have a following Aggregate-Roots, Entities and Value Objects
Aggregate-Roots:
Entities:
Value Objects:
Catalog
and Category
CatalogCategory
represents the instance of Category
in specific Catalog
Category
and Category
Catalog
, the categories can be organized as tree structure. Therefore, the CatalogCategory
can have another as its parent.Product
, Category
and Catalog
CatalogProduct
represents the instance of Product
in specific CatalogCategory
DDD.ProductCatalog.Application.Commands
: for Create, Update and delete operators by consuming repositories.DDD.ProductCatalog.Application.Queries
: for all of the query operators by using Dapper
I want to use Strongly-Typed Ids for all models (i.e. CatalogId
, CatalogCategoryId
and so on) because of the benefits that described very well in the series of Using strongly-typed entity IDs to avoid primitive obsession part 1, part-2, part-3. Therefore, I have to add some advance steps to accomplish this need
Use Value Conversion feature to define the mapping.
builder
.Property(x => x.Id)
.UsePropertyAccessMode(PropertyAccessMode.Field)
.HasConversion(x => x.Id, id => (CatalogId)id);
Custom SqlMapper.TypeHandler
public class StronglyTypedIdMapper<TIdenity> : SqlMapper.TypeHandler<TIdenity> where TIdenity : IdentityBase
{
#region Overrides of TypeHandler<TIdenityType>
public override void SetValue(IDbDataParameter parameter, TIdenity value)
{
parameter.Value = value.Id;
}
public override TIdenity Parse(object value)
{
return IdentityFactory.Create<TIdenity>(value);
}
#endregion
}
Custom TypeConverter
public class StronglyTypedIdConverter<TIdentity> : TypeConverter where TIdentity : IdentityBase
{
#region Overrides of TypeConverter
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
var stringValue = value as string;
if (!string.IsNullOrEmpty(stringValue) && Guid.TryParse(stringValue, out var guid))
{
return IdentityFactory.Create<TIdentity>(guid);
}
return base.ConvertFrom(context, culture, value);
}
#endregion
}
Custom JsonConverter
public class IdentityJsonConverter<TIdentity> : JsonConverter<TIdentity> where TIdentity : IdentityBase
{
public override bool CanConvert(Type typeToConvert)
{
return typeToConvert == typeof(TIdentity);
}
public override TIdentity Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return IdentityFactory.Create<TIdentity>(reader.GetGuid());
}
public override void Write(Utf8JsonWriter writer, TIdentity value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.Id);
}
}
DDD.ProductCatalog.Core.Tests
DDD.ProductCatalog.Infrastructure.EfCore.Tests
DDD.ProductCatalog.Application.Commands.Tests
DbSet
.DDD.ProductCatalog.Application.Queries.Tests
DDD.ProductCatalog.WebApi.Tests
For every test project, I use the following packages
connection-string
dotnet tool install --global Cake.Tool --version 3.1.0
docker compose -f docker-compose.yaml up -d
dotnet-cake.exe "./cake/dev.cake" --target="Tye" --verbosity=normal
http://localhost:5009
dotnet-cake.exe "./cake/report-tests.cake" --target="Report" --verbosity=normal
code_coverage
folder, and open the index.html
by browser to see the reportIf you liked this project or if it helped you, please give a star :star2: for this repository. Thank you!!!