简体   繁体   English

在EF6中使用枚举作为FK

[英]Use enum as FK in EF6

We have a enum Supplier 我们有一个枚举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 所以在99.9%的域名代码中我们对enum的操作就像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. 但是现在我们还添加了product.SupplierInfo.CanAdjustPickupTime ,其中SupplierInfo是一个实体而不仅仅是一个简单的枚举类型。

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. 指定表达式的ResultType与所需类型不兼容。 The expression ResultType is 'MyApp.Model.Suppliers' but the required type is 'Edm.Int32'. 表达式ResultType是'MyApp.Model.Suppliers',但所需的类型是'Edm.Int32'。 Parameter name: keyValues[0] 参数名称: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. SupplierId:名称:类型中的每个属性名称必须是唯一的。 Property name 'SupplierId' is already defined. 已定义属性名称“SupplierId”。

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. 我可以将SupplierId定义为使用HasForeignKey的Property属性然后我需要更改为.SuppliedId == (int)Suppliers.FedEx等不是真正的解决方案。

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 我还可以添加一个使用SupplierId属性作为支持字段的属性枚举,但这不适用于Expressions,因为它需要使用实际映射的数据库属性

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. 在方法OnModelCreating我什么都没写。 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 . 在数据库中:在表中协议我有外键AgreementStateId - 它是表AgreementState的链接。 Everything is working. 一切正常。 For example: 例如:

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

I use enum how foreign key. 我用enum怎么外键。

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. (我使用的是EF6,.NET 4.5)因此,如果在代码中创建类型Enum,则无法与其他属性虚拟创建关系。

//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. 如果您创建了类型枚举,则意味着您不需要表格返回数据来进行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. 我发现处理此方案的最佳方法是将供应商映射为常规域对象,并创建单独的已知供应商ID类。

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; 当您的代码需要检查供应商时,它可以比较ID; 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. 我更喜欢使用一类常量而不是枚举的原因是该模式也适用于字符串比较,并且不需要强制转换。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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