在Nhibernate中映射本地化表

时间:2013-03-24 22:10:57

标签: c# nhibernate fluent-nhibernate nhibernate-mapping fluent-nhibernate-mapping

我正在构建一个本地化的应用程序所有数据都需要以不同语言提供。作为存储模型,我尝试使用Nhibernate,因为它比Entity Framework具有更好的性能。我将根节点存储在数据库中以获取实体的唯一ID,然后我有第二个表,其中包含每种语言的子节点(区域设置表)。

我的数据库表格如下:

Country
   Int Id;
Country_Locale
   Int Id;
   Int CountryId;
   String LangCode;
   String Name;

City
   Int Id;
   Int CountryId;
City_Locale
   Int Id;
   Int CityId;
   String LangCode;
   String Name;

我最喜欢的实体看起来像

Country
  Int Id (from Coutry table)
  String LangCode (from locale table)
  String Name (from locale table)
  IList<City> Cities (Referenced to City entity)
City
  Int Id (From City table)
  String LangCode (from locale table)
  String Name (from locale table)
  Country Country (Referenced to Country entity)
  Int CountryId (From country table)

我意识到我无法映射上面的内容,但它是一种我更喜欢的结构。我怎么能做这个映射或有其他建议。

**  编辑了数据库表格布局,使其更加清晰。

3 个答案:

答案 0 :(得分:1)

我采用类似的方法进行第一次尝试使用单独的表格,最后我坚持使用它并且效果很好。这是我的Fluent Mapping文件(我正在使用Fluent NHibernate)和一些用于从数据库中检索数据的示例代码:

using FluentNHibernate.Mapping;

namespace Core.Mapping
{    
    public class CountryMap : ClassMap<Country>
    {
        public CountryMap()
        {
            Id(x => x.Id);

            Map(x => x.IsoCode)
                .Length(2)
                .Not.Nullable();

            HasMany(x => x.Translations)
                .Fetch.Join()
                .Not.LazyLoad()
                .Cascade.AllDeleteOrphan();
        }
    }
}

Country翻译实际上是作为一个单独的类/表存储的,我发现它并不是你想要的,但是效果很好,因为最后 你有一个表您的所有翻译都已存储 。以下是Fluent映射类:

using FluentNHibernate.Mapping;

namespace Core.Mapping
{
    public class CountryTranslationMap : ClassMap<CountryTranslation>
    {
        public CountryTranslationMap()
        {
            Id(x => x.Id);

            Version(x => x.LastModified);

            Map(x => x.Culture)
                .Length(2)
                .Not.Nullable();

            Map(x => x.Name)
                .Length(50)
                .Not.Nullable();

            References(x => x.Country);
        }
    }

}

以下是我的数据访问层中的一些示例,用于通过Culture或ISO代码检索国家/地区(这里我使用的是NHibernate QueryOver语法):

    public IList<Country> GetAll(string culture)
    {
        var countryLanguageValue = new CountryTranslation();

        IList<Country> results = UnitOfWork.CurrentSession.QueryOver<Country>()
            .Fetch(x => x.Translations).Eager
            .JoinAlias(q => q.Translations, () => countryLanguageValue, JoinType.LeftOuterJoin)
            .Where(() => countryLanguageValue.Culture == culture)
            .OrderBy(x => x.DisplayOrder).Asc
            .List();

        return results;

    }

    public Country GetCountryByIsoCode(string isoCode)
    {
        var result = UnitOfWork.CurrentSession.QueryOver<Country>()
            .Where(x => x.IsoCode == isoCode)
            .List()
            .FirstOrDefault();

        return result;
    }

答案 1 :(得分:0)

您可以将自己的计算属性添加到实体,以从City的子国家/地区检索诸如CountryId之类的内容,并在City对象上具有CountryId属性,因为映射器将使用实际的Country实体替换该Id字段。

public int CountryId { get { return this.Country.Id; } }

不幸的是,如果你在某些(对我来说似乎没有必要),数据库的表而不是其他表上保留_前缀,我认为自动映射会很痛苦;如果您可以消除您的表格看起来非常适合自动化,如本指南中关于其维基的解释:

https://github.com/jagregory/fluent-nhibernate/wiki/Auto-mapping

答案 2 :(得分:0)

我认为这里棘手的问题是您希望CountryId实体可以访问City。我没有确切地知道为什么,因为您已经引用了您所在的国家/地区而只是从您Country.Id City进行了var countryID = myCityEntity.Country.Id;

public int CountryId {
    get {
        return this.Country.Id;
    }
}

顺便说一句,如果你出于某种特殊原因需要这个,你甚至不需要映射它,只需用Domain Drive Design方式而不是普通的POCO来思考,让实体这样做。

{{1}}