Nie byłem na tyle odważny, aby spróbować użyć NHibernate z systemem typu F #, ale może to pomóc w spojrzeniu z perspektywy tego, co faktycznie zostało wygenerowane przez kompilator F #.
Jeśli spojrzysz na swój dyskryminowany związek w odbiciu, generowane są trzy klasy (i więcej, jeśli zliczysz prywatne serwery proxy debugowania).
public abstract class RequestInfo : IStructuralEquatable, IComparable, IStructuralComparable
Pierwsza klasa, RequestInfo, jest abstrakcyjna i jest faktycznie implementowana przez inne typy w unii.
// 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);
}
więc kiedy zrobić:
let r=Id(5)
let s=Name("bob")
r i s są przypadki _id i _name odpowiednio.
Tak więc odpowiedź na Twoje pytanie jest prawdopodobnie odpowiedzią na jedno z poniższych pytań:
- Jak mogę mapować do klasy abstrakcyjnej w NHibernate?
- Jak mogę NHibernate użyć metody fabrycznej?
- Jak mogę utworzyć mapę Nhibernate na niezmienne obiekty?
- Jak zaimplementować niestandardowy typ w NHibernate (prawdopodobnie z IUserType).
Niestety, nie jestem wystarczająco doświadczony, aby dać ci spójną odpowiedź na którekolwiek z tych pytań, ale jestem pewien, że ktoś tutaj wykonał przynajmniej jedno z tych trzech rozwiązań.
Chciałbym myśleć, że można użyć tych samych metod, co w przypadku strategii dziedziczenia, na przykład przy użyciu kolumny dyskryminacyjnej, ale obawiam się, że brak domyślnego konstruktora sprawia, że jest to problematyczne. Więc jestem skłonny pomyśleć, że używanie niestandardowego typu jest rozwiązaniem.
Po pewnym fiddling, oto (ewentualnie wadliwy i czy uszkodzony) niestandardowy typ użytkownika:
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
Ten kod może z pewnością być bardziej uniwersalne, a prawdopodobnie powinien być na aktualnej warstwie domeny, ale pomyślałem, że przydałoby się ukłuć przy implementacji F # IUserType.
Plik mapowania by następnie zrobić coś takiego:
<property name="IdOrName" type="MyNamespace.RequestInfoUserType, MyAssembly" >
<column name="Type"/>
<column name="Id"/>
<column name="Name"/>
</property>
Prawdopodobnie można uciec bez kolumnie „Type” z lekkim uszczypnąć do kodu niestandardowego UserType.
Nie wiem, jak te niestandardowe typy użytkowników działają z zapytaniami/ICriteria, ponieważ tak naprawdę nie pracowałem wcześniej z niestandardowymi typami użytkowników.
Bardzo interesujące pytanie. Jestem dość biegły w NHibernate i F #, poradzę sobie z tym, kiedy dostanę trochę czasu. –
Co najmniej z mojego doświadczenia, miałem ciężki czas używając NHibernate z F #, głównie dlatego, że NHibernate wymaga, aby obiekty miały domyślny konstruktor (który jest często nie w przypadku typów złącz, typów rekordów i większości klas) i opiera się na zmienności, aby przypisać wartości do klas (co często jest denerwujące w radzeniu sobie z definicjami klasy F #). Częściej niż nie, dostaję bazę danych do gry z F # przez toczenie własnego mirco-ORM. – Juliet
Tak, w naszym ostatnim projekcie po prostu trzymaliśmy się starych typów obiektów, aby ładnie się bawić z NHibernate. Tym razem chciałbym się trochę rozgałęzić i wypróbować bardziej realistyczne modele. – MichaelGG