Я недостаточно смел, чтобы попытаться использовать NHibernate с системой типов F #, но это может помочь взглянуть с точки зрения того, что на самом деле генерируется компилятором F #.
Если вы посмотрите на свой Дискриминационный Союз в отражателе, на самом деле сгенерировано три класса (и больше, если вы посчитаете частные прокси отладки).
public abstract class RequestInfo : IStructuralEquatable, IComparable, IStructuralComparable
Первый класс, RequestInfo, является абстрактным и фактически реализуется другими типами в объединении.
// Nested Types
[Serializable, DebuggerTypeProxy(typeof(Program.RequestInfo._Id@DebugTypeProxy)), 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(Program.RequestInfo._Name@DebugTypeProxy)), 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 использовать фабричный метод?
- Как мне создать карту 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.
Я не знаю, как эти пользовательские типы пользователей работают с запросами / критериями, так как раньше я не очень много работал с пользовательскими типами.