简体   繁体   中英

Use enum as FK in EF6

We have a enum Supplier

But now we need to also have some Domain data on that relation

So in 99.9% in the domain code we doe operations on the enum like product.Supplier == Suppliers.FedEx

But now we also have added product.SupplierInfo.CanAdjustPickupTime where SupplierInfo is a Entity and not just a simple enum type.

I have tried these configs

Property(p => p.Supplier)
    .IsRequired()
    .HasColumnName("SupplierId");

HasRequired(p => p.SupplierInfo)
    .WithMany()
    .HasForeignKey(p => p.Supplier); //I have also tried casting to int doing .HasForeignKey(p => (int)p.Supplier)

This will fail with

The ResultType of the specified expression is not compatible with the required type. The expression ResultType is 'MyApp.Model.Suppliers' but the required type is 'Edm.Int32'. Parameter name: keyValues[0]

Also tried

Property(l => l.Supplier)
    .IsRequired()
    .HasColumnName("SupplierId");

HasRequired(p => p.SupplierInfo)
    .WithMany()
    .Map(m => m.MapKey("SupplierId"));

This will offcourse give the good old

One or more validation errors were detected during model generation:

SupplierId: Name: Each property name in a type must be unique. Property name 'SupplierId' is already defined.

I could offcourse define SupplierId as a Property use that with HasForeignKey But then I need to change to .SuppliedId == (int)Suppliers.FedEx etc. Not really a solution.

I could also add a property enum that uses the SupplierId property as backing field, but this will not work with Expressions since it needs to use real mapped DB properties

Any ideas?

I have classes:

public class Agreement
{
    public int Id { get; set; }
    public AgreementStateTypeEnum AgreementStateId { get; set; }
}

public class AgreementState
{
    public int Id { get; set; }
    public string Title { get; set; }
}

context:

 public class AgreementContext :DbContext
 {
     public AgreementContext() : base("SqlConnection") { }
     public DbSet<Agreement> Agreements { get; set; }
 }

In method OnModelCreating I wrote nothing. My enum:

 public enum AgreementStateTypeEnum : int
 {
        InReviewing = 1,
        Confirmed = 2,
        Rejected = 3 
 }

In database: in table Agreements I have foreign key AgreementStateId - it is link to table AgreementStates . Everything is working. For example:

var temp = context.Agreements.First(x => x.AgreementStateId == AgreementStateTypeEnum.Confirmed);

I use enum how foreign key.

Finally I found the problem. (I'm using EF6, NET 4.5) So, if you create a type Enum in your code, you couldn't create a relationship with other property virtual.

//This is wrong, when do you create a foreignkey using a type  enum
//Do You should remove that's code on in your class Map.
 HasRequired(p => p.SupplierInfo)
.WithMany()
.HasForeignKey(p => p.Supplier); //I have also tried casting to int doing 
.HasForeignKey(p => (int)p.Supplier)

If did you created a type enum it means that you don't need for a table return data throught for a join in EF. So, the correct code it is:

public class MyClass{

public enum myEnumType {
FedEx,
Olther
} 

public int id {get;set;}
public myEnumType Supplier {get;set;}

}

//My class Map (using Fluent...)    
public class MyClassMap {

HasKey(t => t.Id);
Property(t => t.Id).HasColumnName("Id");
//The type [supplier] should be [int] in database.
Property(t => t.Supplier).HasColumnName("supplier");
//That's all, you don't need write relationship, int this case 
//Because, when the data returns, the EF will to do the conversion for you.

}

I hope that's useful

The best way I have found to deal with this scenario is to map Supplier as a regular domain object and create a separate class of known supplier IDs.

public class KnownSupplierIds
{
    public const int FedEx = 1;
    public const int UPS = 2;
    // etc.
}

if (product.Supplier.SupplierId == KnownSupplierIds.Fedex) { ... };

When your code needs to check the supplier, it can compare the IDs; when you need additional info from the domain model you just load the Supplier. The reason I prefer using a class of constants instead of an enum is that the pattern works for string comparisons also and there's no need to cast.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM