Fluent Nhibernateのコンポーネントプロパティへのiusertypeをマッピングする
-
28-10-2019 - |
質問
私は実装しようとしています IUserType
2文字のコード(データベースに保存されているもの)とフルネームの両方にアクセスできる州および国コードの場合。 Nhibernate 3.0 Cookbook(p。225)の例に従っていますが、私の問題は私の問題です StreetAddress
クラスは現在、自動化構成のコンポーネントとしてマッピングされています。
public override bool IsComponent(Type type)
{
return type == typeof(StreetAddress);
}
このクラスがコンポーネントとして識別されていると、どのように使用できるかわかりません IUserType
コンポーネントクラスのプロパティの場合、そのクラスは明示的にマッピングされていないためです。流fluentなnhibernateに使用するように言うことができない場所はありません IUserType
仕様。
解決
@firoは近かったが、はるかに簡単な解決策があることが判明した。ここには2つのステップがありました。最初に、私は流fluentなnhibernateにマッピングしないように言わなければなりませんでした State
と Country
私のドメインレイヤーに存在するクラス:
public override bool ShouldMap(Type type)
{
return type.Name != "State" && type.Name != "Country";
}
次に、私は単に慣習を作成する必要がありました IUserType
クラス。これは@Firoが示唆するよりも簡単であることが判明しました:
public class CountryUserTypeConvention : UserTypeConvention<CountryType>
{
}
public class StateUserTypeConvention : UserTypeConvention<StateType>
{
}
それらの定義 IUserTypes
元の質問で参照されている料理本から引き出されましたが、あなたがそれを読みたくない場合に備えて:
public class CountryType : GenericWellKnownInstanceType<Country, string>
{
// The StateType is pretty much the same thing, only it uses "StateCode" instead of "CountryCode"
private static readonly SqlType[] sqlTypes =
new[] {SqlTypeFactory.GetString(2)};
public CountryType()
: base(new Countries(),
(entity, id) => entity.CountryCode == id,
entity => entity.CountryCode)
{
}
public override SqlType[] SqlTypes
{
get { return sqlTypes; }
}
}
そしてそれは由来します GenericWellKnownInstanceType
:
[Serializable]
public abstract class GenericWellKnownInstanceType<T, TId> :
IUserType where T : class
{
private Func<T, TId, bool> findPredicate;
private Func<T, TId> idGetter;
private IEnumerable<T> repository;
protected GenericWellKnownInstanceType(
IEnumerable<T> repository,
Func<T, TId, bool> findPredicate,
Func<T, TId> idGetter)
{
this.repository = repository;
this.findPredicate = findPredicate;
this.idGetter = idGetter;
}
public Type ReturnedType
{
get { return typeof (T); }
}
public bool IsMutable
{
get { return false; }
}
public new bool Equals(object x, object y)
{
if (ReferenceEquals(x, y))
{
return true;
}
if (ReferenceEquals(null, x) ||
ReferenceEquals(null, y))
{
return false;
}
return x.Equals(y);
}
public int GetHashCode(object x)
{
return (x == null) ? 0 : x.GetHashCode();
}
public object NullSafeGet(IDataReader rs,
string[] names, object owner)
{
int index0 = rs.GetOrdinal(names[0]);
if (rs.IsDBNull(index0))
{
return null;
}
var value = (TId) rs.GetValue(index0);
return repository.FirstOrDefault(x =>
findPredicate(x, value));
}
public void NullSafeSet(IDbCommand cmd,
object value, int index)
{
if (value == null)
{
((IDbDataParameter) cmd.Parameters[index])
.Value = DBNull.Value;
}
else
{
((IDbDataParameter) cmd.Parameters[index])
.Value = idGetter((T) value);
}
}
public object DeepCopy(object value)
{
return value;
}
public object Replace(object original,
object target, object owner)
{
return original;
}
public object Assemble(object cached, object owner)
{
return cached;
}
public object Disassemble(object value)
{
return value;
}
/// <summary>
/// The SQL types for the columns
/// mapped by this type.
/// </summary>
public abstract SqlType[] SqlTypes { get; }
}
これらのクラスのリポジトリは、 ReadOnlyCollection
の State
と Country
オブジェクト。繰り返しますが、料理本から:
public class States : ReadOnlyCollection<State>
{
// Truncated in the interest of brevity
public static State Arizona = new State("AZ", "Arizona");
public static State Florida = new State("FL", "Florida");
public static State California = new State("CA", "California");
public static State Colorado = new State("CO", "Colorado");
public static State Oklahoma = new State("OK", "Oklahoma");
public static State NewMexico = new State("NM", "New Mexico");
public static State Nevada = new State("NV", "Nevada");
public static State Texas = new State("TX", "Texas");
public static State Utah = new State("UT", "Utah");
public States() : base(new State[]
{
Arizona, Florida, California, Colorado,
Oklahoma, NewMexico, Nevada, Texas, Utah
}
)
{
}
}
うまくいけば、これは誰かを助けます。
他のヒント
私はそれをテストすることができませんでしたが、それはコンベンションを使用して可能になるはずです
public class ComponentConvention : IComponentConvention, IComponentConventionAcceptance
{
public void Accept(IAcceptanceCriteria<IComponentInspector> criteria)
{
criteria.Expect(x => x.Type == typeof(StreetAddress);
}
public void Apply(IComponentInstance instance)
{
instance.Properties.First(p => p.Name == "CountrCode").CustomType<MyUserType>();
}
}