Reputation: 558
I'm using enumeration classes based on this article from Jimmy Bogard in my domain model. However, EF treats the classes as entities and wants a key to be defined.
Is there a way to make EF store the values from the enumeration classes like it does it with standard C# enums?
This is how I currently implemented the enumeration class:
public class ReservationStatus : Enumeration
{
public static readonly ReservationStatus Outstanding = new ReservationStatus(0, "Oustanding");
public static readonly ReservationStatus Paid = new ReservationStatus(1, "Paid");
public static readonly ReservationStatus Canceled = new ReservationStatus(2, "Canceled");
public static readonly ReservationStatus Rejected = new ReservationStatus(3, "Rejected");
private ReservationStatus() { }
private ReservationStatus(int value, string displayName) : base(value, displayName) { }
}
public class Reservation : Entity<int>
{
public ReservationStatus Status { get; set; }
}
I'm using EF 7 RC1.
Upvotes: 4
Views: 3471
Reputation: 21
For those using EF Core 3.1 there is a better way to do it. The goal is to have a database table with the enumerations listed.
(1) Define how the enumeration table should look like:
public virtual DbSet<ReservationStatus> ReservationStatuses { get; set; }
public void Configure(EntityTypeBuilder<ReservationStatus> builder)
{
builder.HasKey(x => x.Id);
builder.Property(x => x.Id).HasDefaultValue(1).ValueGeneratedNever().IsRequired();
builder.Property(x => x.Name).IsRequired();
}
(2) Define how the value relates in the reservation entity
public void Configure(EntityTypeBuilder<Reservation> builder)
{
builder.Property(x => x.ReservationStatusId).IsRequired();
builder.HasOne(x => x.ReservationStatus)
.WithMany()
.HasForeignKey(x => x.ReservationStatusId);
}
(3) Seed the enumeration table
if (!await RevervationSatuses.AnyAsync())
{
RevervationSatuses.AddRange(Enumeration.GetAll<RevervationSatus>());
await SaveChangesAsync();
}
Upvotes: 1
Reputation: 7245
For the ones who come across this well referenced thread using EF Core, I usually store custom type enumerations by its value (aka identifier) in the database using type conversions. This extension method can be used in the method OnModelCreating
(or a class that implements IEntityTypeConfiguration<T>
):
internal static class EnumerationConfiguration
{
public static void OwnEnumeration<TEntity, TEnum>(this EntityTypeBuilder<TEntity> builder,
Expression<Func<TEntity, TEnum>> property)
where TEntity : class
where TEnum : Enumeration
{
builder
.Property(property)
.HasConversion(x => x.Id, x => Enumeration.FromId<TEnum>(x));
}
}
Afterwards, an enumeration property can be configured as follows:
internal class SpecimenConfiguration : IEntityTypeConfiguration<Specimen>
{
public void Configure(EntityTypeBuilder<Specimen> builder)
{
builder.OwnEnumeration(x => x.Type);
}
}
The benefits of this approach is that it only stores the identifier (and not the other properties attached to a given derived class of Enumeration
) and supports subclassing of Enumeration
.
The downside is an heavily use of reflection through Enumeration.FromId<TEnum>(x)
. This can be amortized by introducing caching in this method, which is not provided by the linked article of Jimmy Bogard.
Upvotes: 8
Reputation: 205599
In EF6 you could configure your ReservationClass
as ComplexType, ignore the DisplayName
property and map Value
property.
Unfortunately for you, according to these design meeting notes:
In the initial RTM of EF7 we are not planning to enable complex and/or value types.
In other words, you cannot do that in current EF Core.
Upvotes: 1