1

コア アセンブリでこの単純なドメインを想定します。

public class Country
{
    protected ICollection<Province> _provinces = null;

    public virtual int Id { get; protected set; }
    public virtual string Name { get; set; }
    public virtual string IsoCode2 { get; set; }
    public virtual string IsoCode3 { get; set; }
    public virtual int IsoCodeNumeric { get; set; }
    public virtual ICollection<Province> Provinces
    {
        get { return _provinces ?? (_provinces = new List<Province>()); }
        set { _provinces = value; }
    }
}

public class Province
{
    public virtual int Id { get; protected set; }
    public virtual Country Country { get; set; }
    public virtual string Name { get; set; }
    public virtual string Abbreviation { get; set; }
}

私のプレゼンテーション レイヤーのビュー モデルはほぼ同じです。

public class CountryModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string IsoCode2 { get; set; }
    public string IsoCode3 { get; set; }
    public int IsoCodeNumeric { get; set; }
    public int NumberOfProvinces { get; set; }
}

public class ProvinceModel
{
    public int Id { get; set; }
    public int CountryId { get; set; }
    public string Name { get; set; }
    public string Abbreviation { get; set; }
}

ドメインオブジェクト/ビューモデル間で前後にマッピングするためのいくつかの拡張メソッドを作成しています:

public static class Extensions
{
    public static Country ToEntity(this CountryModel model, Country entity = null)
    {
        if (entity == null)
            entity = new Country();
        entity.Name = model.Name;
        entity.IsoCode2 = model.IsoCode2;
        entity.IsoCode3 = model.IsoCode3;
        entity.IsoCodeNumeric = model.IsoCodeNumeric;
        entity.AddressFormat = model.AddressFormat;
        entity.CanBillTo = model.CanBillTo;
        entity.CanShipTo = model.CanShipTo;
        entity.IsPublished = model.IsPublished;
        return entity;
    }

    public static CountryModel ToModel(this Country entity, bool includeProvinceCount = false, CountryModel model = null)
    {
        if (model == null)
            model = new CountryModel();
        model.Id = entity.Id;
        model.Name = entity.Name;
        model.IsoCode2 = entity.IsoCode2;
        model.IsoCode3 = entity.IsoCode3;
        model.IsoCodeNumeric = entity.IsoCodeNumeric;
        model.AddressFormat = entity.AddressFormat;
        model.CanBillTo = entity.CanBillTo;
        model.CanShipTo = entity.CanShipTo;
        model.IsPublished = entity.IsPublished;
        if (includeProvinceCount)
            model.NumberOfProvinces = entity.Provinces.Count;
        return model;
    }

    public static Province ToEntity(this ProvinceModel model, Province entity = null)
    {
        if (entity == null)
            entity = new Province();
        //entity.Country = LoadCountryById(model.CountryId); ???? <-- HERE
        entity.Name = model.Name;
        entity.Abbreviation = model.Abbreviation;
        entity.CanBillTo = model.CanBillTo;
        entity.CanShipTo = model.CanShipTo;
        entity.IsPublished = model.IsPublished;
        return entity;
    }

    public static ProvinceModel ToModel(this Province entity, ProvinceModel model)
    {
        if (model == null)
            model = new ProvinceModel();
        model.Id = entity.Id;
        model.CountryId = entity.Country.Id;
        model.Name = entity.Name;
        model.Abbreviation = entity.Abbreviation;
        model.CanBillTo = entity.CanBillTo;
        model.CanShipTo = entity.CanShipTo;
        model.IsPublished = entity.IsPublished;
        return model;
    }
}

Entity Framework では、Province ドメイン オブジェクトに Country プロパティと対応する CountryId プロパティの両方が含まれていました。CountryId を設定するだけで国を割り当てることができます。

NHibernate では、ドメイン作成時に外部キーの id は不要です。では、ProvinceModel CountryId を Country オブジェクトにマップするにはどうすればよいでしょうか。

物事をインターフェースに抽象化し、依存性注入を使用するために、あらゆる種類の手順を実行しました。マッピング拡張機能内からサービス ロケーターを使用して検索する必要がありますか? マッピング拡張の外で国を検索し、拡張メソッドのパラメーターとしてそれを要求する必要がありますか? このシナリオを処理するための推奨される方法は何ですか?


次に、NHibernate では、関連付けを維持するためにヘルパー関数をドメイン オブジェクトに追加することを推奨しています (肯定的ではありませんが、EF はこれを「自動的に」処理すると思います)。たとえば、SetCountryProvince にメソッドを追加し、 CountryAddProvinceにメソッドを追加します。RemoveProvince

これはパフォーマンスに影響しませんか? 州 (関連付けが管理されている場所) に単に国を設定する代わりに、新しい国の州のリスト全体が読み込まれ、コレクションに追加する前にリストに既に存在するかどうかが確認されます。 old Country の Provinces が読み込まれ、その州をコレクションから削除する必要があるかどうかが確認されます。

4

1 に答える 1

1

[EF で] CountryId を設定するだけで国を割り当てることができました。

これは正しくありません。私の意見では、これは Entity Framework の重大な欠陥です。Country と CountryId の両方のプロパティを持つことは、CountryId を設定することによってデータベースから取得せずに Country を設定できるハックです。Web アプリでは、CountryId 外部キーが設定された状態でレコードが保存されるため、これは機能します。次にレコードを読み込むと、Country が入力されます。このパターンに対する NHibernate のソリューションISession.Loadは、動的プロキシを作成する方法です。

あなたの例では、次のようなことをします

province.Country = session.Load<Country>(provinceModel.CountryId);

2 番目の質問については、通常、メソッドを使用してコレクションへのアクセスをカプセル化するだけです。これにより、コレクション自体がセッターに置き換えられず、関係の両側を維持できます。これを次のようにモデル化します。

public class Country
{
    private ICollection<Province> _provinces;

    public Country()
    {
        _provinces = new HashSet<Province>();
    }

    public virtual IEnumerable<Province> Provinces
    {
        get { return _provinces; }
    }

    public virtual void AddProvince(Province province)
    {
        province.Country = this;
        _provinces.Add(province);
    }

    public virtual void RemoveProvince(Province province)
    {
        province.Country = null;
        _provinces.Remove(province);
    }
}

ご指摘のとおり、これにはコレクションのロードが必要です。NHibernate (および Hibernate) はもともとステートフル アプリケーション用に設計されたものであり、使用パターンの多くはステートレス Web アプリケーションでは必ずしも必要ではないことを覚えておく必要があります。ただし、これらのパターンの一部から逸脱する前に、パフォーマンスのプロファイルを作成します。たとえば、オブジェクトをコミットする前に検証する必要があり、そのためにはメモリ内表現が一貫している必要があります。

于 2013-09-19T15:36:25.347 に答える