Ответ 1
Я не был достаточно храбр, чтобы попробовать использовать NHibernate с системой типа F #, но это может помочь взглянуть с точки зрения того, что на самом деле сгенерировано компилятором F #.
Если вы посмотрите на свой Дискриминационный союз в отражателе, на самом деле есть три генерируемых класса (и больше, если вы считаете частные прокси-серверы отладки).
public abstract class RequestInfo : IStructuralEquatable, IComparable, IStructuralComparable
Первый класс, RequestInfo, является абстрактным и фактически реализуется другими типами в объединении.
// Nested Types
[Serializable, DebuggerTypeProxy(typeof([email protected])), DebuggerDisplay("{__DebugDisplay()}")]
public class _Id : Program.RequestInfo
{
// Fields
[DebuggerBrowsable(DebuggerBrowsableState.Never), CompilerGenerated, DebuggerNonUserCode]
public readonly int id1;
// Methods
[CompilerGenerated, DebuggerNonUserCode]
public _Id(int id1);
}
[Serializable, DebuggerTypeProxy(typeof([email protected])), DebuggerDisplay("{__DebugDisplay()}")]
public class _Name : Program.RequestInfo
{
// Fields
[DebuggerBrowsable(DebuggerBrowsableState.Never), CompilerGenerated, DebuggerNonUserCode]
public readonly string name1;
// Methods
[CompilerGenerated, DebuggerNonUserCode]
public _Name(string name1);
}
поэтому, когда вы выполните:
let r=Id(5)
let s=Name("bob")
r и s - экземпляры _Id и _Name соответственно.
Итак, ответ на ваш вопрос, скорее всего, ответит на один из следующих вопросов:
- Как сопоставить абстрактный класс в nhibernate?
- Как я могу заставить NHibernate использовать метод factory?
- Как создать карту Nhibernate для неизменяемых объектов?
- Как реализовать собственный тип в NHibernate (предположительно с IUserType).
К сожалению, я недостаточно разбираюсь, чтобы дать вам последовательный ответ на любой из этих вопросов, но я уверен, что кто-то еще здесь сделал хотя бы одно из этих трех решений.
Мне бы хотелось подумать, что вы можете использовать те же методы, которые использовались для стратегий наследования, используя, например, столбец дискриминатора, но я боюсь, что отсутствие конструктора по умолчанию делает это проблематичным. Поэтому я склонен думать, что использование настраиваемого типа - это решение.
После некоторого ворчания, здесь (возможно, багги и/или сломанный) пользовательский тип пользователя:
type RequestInfo =
| Id of int
| Name of string
type RequestInfoUserType() as self =
interface IUserType with
member x.IsMutable = false
member x.ReturnedType = typeof<RequestInfo>
member x.SqlTypes = [| NHibernate.SqlTypes.SqlType(Data.DbType.String); NHibernate.SqlTypes.SqlType(Data.DbType.Int32); NHibernate.SqlTypes.SqlType(Data.DbType.String) |]
member x.DeepCopy(obj) = obj //Immutable objects shouldn't need a deep copy
member x.Replace(original,target,owner) = target // this might be ok
member x.Assemble(cached, owner) = (x :> IUserType).DeepCopy(cached)
member x.Disassemble(value) = (x :> IUserType).DeepCopy(value)
member x.NullSafeGet(rs, names, owner)=
// we'll use a column as a type discriminator, and assume the first mapped column is an int, and the second is a string.
let t,id,name = rs.GetString(0),rs.GetInt32(1),rs.GetString(2)
match t with
| "I" -> Id(id) :> System.Object
| "N" -> Name(name) :> System.Object
| _ -> null
member x.NullSafeSet(cmd, value, index)=
match value with
| :? RequestInfo ->
let record = value :?> RequestInfo
match record with
| Id(i) ->
cmd.Parameters.Item(0) <- "I"
cmd.Parameters.Item(1) <- i
| Name(n) ->
cmd.Parameters.Item(0) <- "N"
cmd.Parameters.Item(2) <- n
| _ -> raise (new ArgumentException("Unexpected type"))
member x.GetHashCode(obj) = obj.GetHashCode()
member x.Equals(a,b) =
if (Object.ReferenceEquals(a,b)) then
true
else
if (a=null && b=null) then
false
else
a.Equals(b)
end
Этот код, безусловно, может быть более общим и, вероятно, не должен быть в вашем реальном доменном слое, но я подумал, что было бы полезно взять удар в реализации FU IUserType.
Затем ваш файл сопоставления сделает следующее:
<property name="IdOrName" type="MyNamespace.RequestInfoUserType, MyAssembly" >
<column name="Type"/>
<column name="Id"/>
<column name="Name"/>
</property>
Вероятно, вы можете уйти без столбца для "Тип" с небольшой настройкой на пользовательский код UserType.
Я не знаю, как эти пользовательские типы пользователей работают с запросами /ICriteria, поскольку я до сих пор не работал с пользовательскими типами пользователей.