实体框架 - 与假外键的关系(数据库中没有外键)

Jar*_*rek 8 entity-relationship entity-framework ef-code-first

我有很多表有TextID列引用转换表.翻译表还需要LanguageID来获得所需语言的翻译文本.我的问题是我的数据库中没有LanguageID,它是在系统中预定义的,我不知道如何使用Fluent API定义它,即这可以是我的模型:

public partial class MyEntity
{    
    public short ID { get; set; }
    public Nullable<int> TextID { get; set; }
    [NotMapped]
    public Nullable<int> LanguageID { get; set; }
    public virtual TEXT_TRANSLATION Translation { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

和翻译表:

public partial class TEXT_TRANSLATION
{
    [Key, Column(Order = 0)]
    public int TextID { get; set; }

    [Key, Column(Order = 1)]
    public int LanguageID { get; set; }

    public string TranslatedText { get; set; } 
}
Run Code Online (Sandbox Code Playgroud)

基本上我需要这样的导航:

myEntity.Translation.TranslatedText
Run Code Online (Sandbox Code Playgroud)

使用SQL时,我会这样做:

Left Join TEXT_TRANSLATION ON 
  MyEntity.TextID = TEXT_TRANSLATION.TextID 
  AND TEXT_TRANSLATION.LanguageID = 1033 
Run Code Online (Sandbox Code Playgroud)

基本上我想使用TextID外键并获得一个翻译 - LanguageID是静态的,并在上下文中预定义.

我无法更改现有的数据库架构.如果我不需要在我的代码中映射LanguageID字段,只需在映射中使用它就像系统参数一样,这将是完美的.EF甚至可以吗?

Lad*_*nka 5

如果你LanguageID是静态的,你可以尝试使用这个hack.

定义您的实体,如:

public class Entity {
    public int Id { get; set; }
    public int TextId { get; set; }
    public Translation Translation { get; set; }
}

// No LanguageId in translation
public class Translation {
    public int TextId { get; set; }
    public string TranslatedText { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

OnModelCreating在您的派生中添加这个流畅的映射DbContext:

// Define foreign key
modelBuilder.Entity<Entity>()
            .HasRequired(e => e.Translation)
            .WithMany()
            .HasForeignKey(e => e.TextId);

// Trick - EF believes that only TextId is PK. Without this trick you cannot
// make navigation property on your entity
modelBuilder.Entity<Translation>()
            .HasKey(t => t.TextId);

// If you are going to insert translations as well your TextId cannot be 
// handled as autogenerated column
modelBuilder.Entity<Translation>()
            .Property(t => t.TextId)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

// The HACK - conditional mapping. This tells EF to "see" only records
// with LanguageId set to 1033. Without this hack you cannot filter 
// translations for only single language.
modelBuilder.Entity<Translation>()
            .Map(m => {
                        m.Requires("LanguageId").HasValue(1033);
                        m.ToTable("Translations");   
                    });
Run Code Online (Sandbox Code Playgroud)

该hack基于用于TPH映射的概念,但在这种情况下,您只使用单个实体类型来仅加载具有预定义的记录子集LanguageId.即使来自主要实体的FK也应该工作,因为你不能使用相同的翻译TextId- 这意味着它们也具有相同的功能LanguageId,因为TextId并且LanguageId形成主键.

我不确定此解决方案中是否存在任何隐藏问题.我只是试了一下它就行了.