在Nhibernate中映射本地化表

本文关键字:本地化 映射 Nhibernate | 更新日期: 2023-09-27 18:05:30

我正在构建一个本地化的应用程序。所有数据都需要以不同的语言提供。作为一种存储模型,我尝试使用Nhibernate,因为它比实体框架具有更好的性能。我在数据库中存储了一个根节点,以获得实体的唯一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)

我意识到我无法绘制上面的图,但这是我更喜欢的一种结构。我该怎么做这个映射,或者还有其他建议吗。

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

在Nhibernate中映射本地化表

我采用了与您第一次尝试使用单独表类似的方法,最后我坚持了下来,效果很好。以下是我的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();
        }
    }
}

国家/地区翻译实际上是作为一个单独的类/表存储的,我意识到这并不完全是你想要的,但它运行得很好,因为最终你有一个表,所有翻译都存储在其中。以下是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;
    }

您可以将自己计算的属性添加到实体中,以从城市的子国家检索CountryId等内容,并在城市对象上具有CountryId属性,因为映射器将用实际的国家实体替换该Id字段。

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

不幸的是,我认为如果在数据库的某些表(对我来说似乎是不必要的(上保留_前缀,而不在其他表上保留,那么自动映射将是一件痛苦的事情;如果你能消除你的表看起来非常适合自动映射的问题,就像本指南在他们的wiki上解释的那样:

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

我想这里的棘手之处在于,您希望从City实体访问CountryId。我不明白为什么,因为你已经提到了你的国家,只需从你的City中做Country.Id,你就会有它。

var countryID = myCityEntity.Country.Id;

顺便说一句,如果你出于某种特殊原因需要它,甚至不需要映射它,只需以域驱动器设计的方式思考,而不是简单的POCO,并让实体来做这件事。

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