8

変換テーブルを参照するTextID列を持つテーブルがたくさんあります。翻訳テーブルには、目的の言語に翻訳されたテキストを取得するためのLanguageIDも必要です。私の問題は、データベースにLanguageIDがなく、システムで事前定義されており、Fluent APIを使用してLanguageIDを定義する方法がわからないことです。つまり、これが私のモデルになる可能性があります。

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; }
}

そして翻訳表:

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; } 
}

基本的に私はこのようなナビゲーションが必要です:

myEntity.Translation.TranslatedText

SQLを使用している間、私は次のようにします。

Left Join TEXT_TRANSLATION ON 
  MyEntity.TextID = TEXT_TRANSLATION.TextID 
  AND TEXT_TRANSLATION.LanguageID = 1033 

基本的に、TextID外部キーを使用して1つの翻訳のみを取得したい-LanguageIDは静的であり、コンテキストで事前定義されています。

既存のDBスキーマを変更できません。コードでLanguageIDフィールドをマップする必要がなく、システムパラメーターのようにマッピング内で使用するだけでよい場合は完璧です。EFでも可能ですか?

4

3 に答える 3

5

静的な場合LanguageIDは、このハックを使用してみてください。

次のようにエンティティを定義します。

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; }
}

そして、この流暢なマッピングを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");   
                    });

このハックは、TPHマッピングに使用される概念に基づいていますが、この場合、単一のエンティティタイプのみを使用して、事前定義されたレコードのサブセットのみをロードしますLanguageId。主要なエンティティからのFKでさえ、同じもので翻訳する必要がないため、機能するはずですTextId。つまり、同じものを持っていることを意味します。これは、主キーを形成LanguageIdするために不可能です。TextIdLanguageId

このソリューションに隠れた問題があるかどうかはわかりません。簡単に試してみたところ、うまくいきました。

于 2013-01-28T19:00:53.803 に答える
2

T_Tテーブルが巨大であっても、これを別の方法で行う方法がわかりません(少なくとも、「すべてをどこかにロードする」必要があります)。

public static class Translator {
  private static Dictionary<int, Dictionary<int, string>> translations_;

  static Translator() {
    translations_ = new Dictionary<int, Dictionary<int, string>>();
  } 

  public static void PopulateTranslator(Repository repo) {//or something to go to your db
     translations_ = repo.TEXT_TRANSLATIONs.ToList()
                     .GroupBy(m => m.LanguageId)
                     .ToDictionary(g => g.Key, 
                                   g=> g.ToDictionary(x => x.TextID,
                                                      x=> x.TranslatedText)
                                   );
  }
  public static string GetTranslation(int languageId, int? textId) {
      if (textId == null || !translations.ContainsKey(languageId)
         return something or throw;
      var dic = translations[languageId];
      var id = Convert.ToInt32(textId);
      if (!dic.ContainsKey(id)
          return something or throw;

      return dic[id);

  }

Translator.PopulateTranslator(<something to access your db>)ユーザーが翻訳を更新できる場合は、おそらくリセットして、アプリケーションの開始時に呼び出すことになります。

次に、エンティティではなく

public virtual TEXT_TRANSLATION Translation { get; set; }

あなたが持っているだろう

public string TranslatedText {
    get { return Translator.GetTranslation(LanguageID, TextId);}
}

編集 別の方法は、dbデータの代わりにresxファイルを操作することですが、他の制約があると思います。

于 2013-01-28T17:08:59.700 に答える
2

このようなことをした場合はどうなりますか?

public partial class MyEntity
{    
    public short ID { get; set; }
    public Nullable<int> TextID { get; set; }
    [NotMapped]
    public Nullable<int> LanguageID { get; set; }
    public virtual ICollection<TEXT_TRANSLATION> Transations {get;set;}

    public IQueryable<TEXT_TRANSLATION> Translation
    {
      get
      {
          return this.Translations.Where( t => t.LanguageID == this.LanguageID );
      }
    }
}

仮想ICollectionは、言語に関係なくすべての翻訳のリストを格納し、Translationプロパティは.Where()を実行します。

于 2013-01-28T16:43:44.353 に答える