2

私はこれに似た構造を持っています:

public class Entity
{
    public int Id { get; set; }
    public IDictionary<string, EntityLocale> Locales { get; set; }
}
public class EntityLocale
{
    public string Name { get; set; }
}
public class EntityMap : ClassMap<Entity>
{
    public EntityMap()
    {
        HasMany(x => x.Locales)
                .AsMap<string>("Locale")
                .Component(
                c => {
                         c.Map(x => x.Name);
                     }
                );
    }
}

そして、「en」キーで製品ロケールのすべての名前を受け取りたいです。linq では次のようになります。

var names = Session.QueryOver<Product>().List().Select(x => x.Locales["en"].Name).ToList();

nhibernateでこれを達成するにはどうすればよいですか? (それが QueryOver であるか Criteria API であるかは気にしません。すべてを選択したくないだけです)。

アップデート

私は次の醜いハックを思いつきました(これには満足していません。コードにSQLを入れたくありません):

var names = Session.CreateSQLQuery("SELECT Name FROM ProductLocales WHERE Locale = 'en'").List<string>()
4

1 に答える 1

2

このような場合、NHibernate には非常に優れたソリューションがあります: 18.1. Hibernate フィルター。最後に、ディクショナリにフィルタProductを選択して適用します...したがって、.SingleOrDefault()Locales

フィルターの定義

public class CulturFilter : FilterDefinition
{
  public CulturFilter()
  {
    WithName("CulturFilter")
        .AddParameter("culture",NHibernate.NHibernateUtil.String);
  }
}

そしてそれを適用する

HasMany(x => x.Locales)
  .AsMap<string>("Locale")
  ... 
  .ApplyFilter<CulturFilter>("Locale = :culture"))
;

その瞬間から、セッションでフィルターを有効にするたびに (AOP フィルターを使用している場合でも)、 にIDictionary要素が 1 つ (またはまったく含まれない)であることを確認できます。

session.EnableFilter("CultureFilter")
    .SetParameter("culture", "en");

// applied every time
var criteria = session.CreateCritieria...
var query = session.QueryOver....

必要に応じて、いくつかのリンクを含む同様の投稿がありますhttps://stackoverflow.com/a/17109300/1679310

編集:列「ロケール」を直接制限し、名前のリストを取得する

使用できる(そして私が知っている)他のアプローチ(現在のソリューションをほぼ同じに保つ)は、 LocalEntity マッピングを拡張することです

public class EntityLocale
{
    public virtual string CultureName { get; set; }
    public virtual string Name { get; set; }
}
public class EntityMap : ClassMap<Entity>
{
    public EntityMap()
    {
        HasMany(x => x.Locales)
            .AsMap<string>("Locale")
            .Component(
            c => {
                c.Map(x => x.CultureName).Formula("Locale").Not.Insert().Not.Update();
                c.Map(x => x.Name);
            }
        );
    }
}

これにより、次のようにすべての「en」名のリストを取得できます。

var criteria = 
    session.QueryOver<Entity>()
    .JoinQueryOver<IDictionary<string, EntityLocale>>(c => c.Locales)
    .UnderlyingCriteria;

var list = criteria
    .Add(Restrictions.Eq("CultureName", "en"))
    .SetProjection(Projections.SqlProjection("Name"
        , new string[] { "name" }
        , new IType[] { NHibernateUtil.String }))
    .List()
    .Cast<string>()
    .ToList<String>();

Namesこれで、「en」カルチャでフィルタリングされた from EntityLocale をすべて含むリストができました。

于 2013-06-22T05:49:23.173 に答える