Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I've not been brave enough to try using NHibernate with F#'s type system, but it might help to look from the perspective of what's actually generated by the F# compiler.</p> <p>If you look at your Discriminated Union in reflector, there are actually three classes generated (and more if you count the private debug proxies).</p> <pre><code>public abstract class RequestInfo : IStructuralEquatable, IComparable, IStructuralComparable </code></pre> <p>The first class, RequestInfo, is abstract, and is actually implemented by the other types in the union.</p> <pre><code> // 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); } </code></pre> <p>so when you do:</p> <pre><code> let r=Id(5) let s=Name("bob") </code></pre> <p>r and s are instances of _Id and _Name, respectively.</p> <p>So the answer to your question is likely the answer to one of the following questions:</p> <ul> <li>How do I map to an abstract class in nhibernate?</li> <li>How can I make NHibernate use a factory method?</li> <li>How can I create map Nhibernate to immutable objects?</li> <li>How do I do implement a custom type in NHibernate (presumably with IUserType).</li> </ul> <p>Unfortunately, I'm not savvy enough to give you a coherent answer to any of those, but I'm sure someone else here has done at least one of these three solutions.</p> <p>I'd like to think that you can use the same methods used for Inheritance Strategies, using, for example, a discriminator column, but I'm afraid the lack of a default constructor makes this problematic. So I'm inclined to think that using a custom type is the solution.</p> <p>After some fiddling, here's a (possibly buggy and or broken) custom user type:</p> <pre><code>type RequestInfo = | Id of int | Name of string type RequestInfoUserType() as self = interface IUserType with member x.IsMutable = false member x.ReturnedType = typeof&lt;RequestInfo&gt; 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 :&gt; IUserType).DeepCopy(cached) member x.Disassemble(value) = (x :&gt; 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" -&gt; Id(id) :&gt; System.Object | "N" -&gt; Name(name) :&gt; System.Object | _ -&gt; null member x.NullSafeSet(cmd, value, index)= match value with | :? RequestInfo -&gt; let record = value :?&gt; RequestInfo match record with | Id(i) -&gt; cmd.Parameters.Item(0) &lt;- "I" cmd.Parameters.Item(1) &lt;- i | Name(n) -&gt; cmd.Parameters.Item(0) &lt;- "N" cmd.Parameters.Item(2) &lt;- n | _ -&gt; 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 &amp;&amp; b=null) then false else a.Equals(b) end </code></pre> <p>This code could surely be made more generic, and should probably not be in your actual domain layer, but I thought it would be useful to take a stab at a F# implementation of IUserType.</p> <p>Your mapping file would then do something like:</p> <pre><code>&lt;property name="IdOrName" type="MyNamespace.RequestInfoUserType, MyAssembly" &gt; &lt;column name="Type"/&gt; &lt;column name="Id"/&gt; &lt;column name="Name"/&gt; &lt;/property&gt; </code></pre> <p>You probably can get away without a column for "Type" with a slight tweak to the custom UserType code.</p> <p>I don't know how these custom user types work with queries/ICriteria, as I haven't really worked with custom user types much before.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload