EfEnumerationTableGenerator 1.0.0-rc

This is a prerelease version of EfEnumerationTableGenerator.
dotnet add package EfEnumerationTableGenerator --version 1.0.0-rc                
NuGet\Install-Package EfEnumerationTableGenerator -Version 1.0.0-rc                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="EfEnumerationTableGenerator" Version="1.0.0-rc" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add EfEnumerationTableGenerator --version 1.0.0-rc                
#r "nuget: EfEnumerationTableGenerator, 1.0.0-rc"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install EfEnumerationTableGenerator as a Cake Addin
#addin nuget:?package=EfEnumerationTableGenerator&version=1.0.0-rc&prerelease

// Install EfEnumerationTableGenerator as a Cake Tool
#tool nuget:?package=EfEnumerationTableGenerator&version=1.0.0-rc&prerelease                

A source code generator for .NET that aims to solve a problem using the Enumeration class in EF CORE.

Problem:

There is an issue with the mapping of the Enumeration class in Enitity Framework Core. Consider an example:

class Order
{
    private Order(){}
    public OrderStatus Status { get; protected set; }
   
    public void Cancel()
    {
        Status = OrderStatus.Cancelled;
    }
}

class OrderStatus 
{
    public static readonly OrderStatus Completed = new(3, 'Completed');
    public static readonly OrderStatus Cancelled = new(4, 'Cancelled');
    public static readonly IReadOnlyList<OrderStatus> All = new[]{ Completed, Cancelled };
    
    private OrderStatus(int id, string name)
    {
        Id = id;
        Name = name;
    }
    
    private OrderStatus(){}
    
    public int Id { get; protected set; }
    public string Name { get; protected set; }
    
    public OrderStatus FromId(int id){...}
}

We want:

  1. Use the OrderStatus type in the Order class, not int. Because it complies with DDD.
  2. When requesting an Order or setting another value in Status, we do not want to access the database, but want to take a ready-made static instance, for example, OrderStatus.Completed.

If you use OrderStatus as a separate Enitity, and make the Status property in Order navigation, then when setting a static instance to Status, EF will swear for various reasons, for example, that it already has such a tracked instance. 3. We want to store the OrderStatus in the database with all the data. This is necessary so that the relational model is also correct, the Order table has a constraint on the OrderStatus table to limit the allowed values. <br/>

EF (7) does not currently allow this. <br/>

Solution:

One solution is to use ValueConversions on OrderStatus to store only StatusId in Orders (convert between OrderStatus and int). The configuration is done like this: builder.Property(x ⇒ x.Status).HasConversion(x ⇒ x.Id, id ⇒ OrderStatus.FromId(id)).HasColumnName("StatusId")

To store statuses in the database, create a clone class OrderStatusTable, which will be exactly the same as OrderStatus, but on this created class the full table configuration will be performed. Creating a clone class manually is problematic in support, and it duplicates the code.

Therefore, to solve this problem, using the Source Generator, we will create a copy class named OrderStatusTable (the class will be 1 in 1, only Table is added to the end of the name for the class, constructor, etc):

[GeneratedEnumerationTable(typeof(OrderStatus))]
public class EfTableGeneratorContext
{
}

public class OrderConfig : IEntityTypeConfiguration<Order>
{
    public void Configure(EntityTypeBuilder<Order> builder)
    {
        // ...
        builder.Property(x => x.Status).HasConversion(x => x.Id, id => OrderStatus.FromId(id)).HasColumnName("StatusId");
        builder.HasOne<OrderStatusTable>().WithMany().HasForeignKey(x => x.Status);
    }
}

public class OrderStatusConfig : IEntityTypeConfiguration<OrderStatusTable>
{
    public void Configure(EntityTypeBuilder<OrderStatusTable> builder)
    {
        builder.HasKey(x => x.Id);
        builder.HasData(OrderStatusTable.All);
        // ...
    }
}

Thus, OrderStatusTable is a copy of the OrderStatus type, which allows us to configure ValueConversion for OrderStatus, and for OrderStatusTable - storing statuses in a separate table and constraints. <br/> To use, install the EfEnumerationTableGenerator package, create any class, and then add GeneratedEnumerationTable attributes to this class to generate clone classes.

Current restrictions:

The original class (for example, OrderStatus) must be alone in the file to work correctly.

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

  • .NETStandard 2.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.0-rc 82 5/17/2023