------------------------------------------------------------------
#light
namespace StockPrices
open System
open System.Collections.Generic
// ----------------- 1
type COMPANY = class
[<DefaultValue>] val mutable Id : int
[<DefaultValue>] val mutable COMPANY_NAME : string
[<DefaultValue>] val mutable COMPANY_TICKER : string
[<DefaultValue>] val mutable ASSET_TYPE_ID : int
[<DefaultValue>] val mutable IS_ACTIVE : int
new() = {}
end
------------------------------------------------------------------
This is the simplest way of setting up a class in F#.
In this example, I use the default constructor -- these are the open parentheses in the New() statement. Therefore, my properties are not initialized. In F# this is a no no and is not allowed. When you do not initialize a variable you need to use the [<DefaultValue>] attribute to initialize the value to Zero, it that is possible.
From Microsoft: "The DefaultValue attribute is required on explicit fields in class types that have a primary constructor. This attribute specifies that the field is initialized to zero. The type of the field must support zero-initialization."
So, the above statement gives me a class with five public variables -- the integers are initialized with Zeros; the strings are initialized with Nulls.
The following is my main F# program. Note that my COMPANY class is in a module called StockPrices that I open at the start of the program.
-----------------------------------------------------------------------------------------------
#light
open System
open System.Collections.Generic
open System.IO
open StockPrices
open FluentNHibernate.Automapping
open FluentNHibernate
let properties = new Dictionary<string, string>()
properties.Add("connection.provider", "NHibernate.Connection.DriverConnectionProvider")
properties.Add("dialect", "NHibernate.Dialect.MsSql2000Dialect")
properties.Add("connection.driver_class", "NHibernate.Driver.SqlClientDriver")
properties.Add("show_sql", "true")
properties.Add("proxyfactory.factory_class", "NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle")
let connString = "server='BIG_ROCK\LOGGERSEDGE';Initial Catalog=SMDATA;User ID=sa;Password=XXXXX"
properties.Add("connection.connection_string", connString)
//-> The New
let autoMappings = (FluentNHibernate.Automapping.AutoMap.AssemblyOf<StockPrices.COMPANY>()).Where(fun t -> (t.Namespace="StockPrices"))
let aConfig = (new NHibernate.Cfg.Configuration()).AddProperties(properties).AddAutoMappings(autoMappings)
let sessionFactory = aConfig.BuildSessionFactory()
let aSession = sessionFactory.OpenSession()
aSession.BeginTransaction()
//AT&T is Id 100
let coID = 100
let someObj = aSession.Load(typeof<StockPrices.COMPANY>, coID) :?> StockPrices.COMPANY
printfn "Company Name: %s, Ticker: %s" someObj.COMPANY_NAME someObj.COMPANY_TICKER
aSession.Close()
let userresp = Console.ReadLine()
-----------------------------------------------------------------------------------------------
This program craps out on the line:
let aConfig = (new NHibernate.Cfg.Configuration()).AddProperties(properties).AddAutoMappings(autoMappings)
with the error:
{"(XmlDocument)(2,4): XML validation error: The element 'class' in namespace 'urn:nhibernate-mapping-2.2' has incomplete content. List of possible elements expected: 'meta, subselect, cache, synchronize, comment, tuplizer, id, composite-id' in namespace 'urn:nhibernate-mapping-2.2'."}
To be honest, I really have no clue what this all means.
So, I decide to take another tack. I try an F# class that actually uses the 'member' syntax:
-----------------------------------------------------------------------------------------------
type COMPANY() = class
let mutable _Id : int = 0
let mutable _COMPANY_NAME : string = ""
let mutable _COMPANY_TICKER : string = ""
let mutable _ASSET_TYPE_ID : int = 0
let mutable _IS_ACTIVE : int = 0
member x.Id with get() = _Id and set(v) = _Id <- v
member x.COMPANY_NAME with get() = _COMPANY_NAME and set(v) = _COMPANY_NAME <- v
member x.COMPANY_TICKER with get() = _COMPANY_TICKER and set(v) = _COMPANY_TICKER <- v
member x.ASSET_TYPE_ID with get() = _ASSET_TYPE_ID and set(v) = _ASSET_TYPE_ID <- v
member x.IS_ACTIVE with get() = _IS_ACTIVE and set(v) = _IS_ACTIVE <- v
end
-----------------------------------------------------------------------------------------------
I rerun the my program.
This time, I make it one more line before it crashes on the line:
let sessionFactory = aConfig.BuildSessionFactory()
This time I get this big ugly:
NHibernate.InvalidProxyTypeException was unhandled
Message="The following types may not be used as proxies:
StockPrices.COMPANY: method get_Id should be 'public/protected virtual' or 'protected internal virtual'
StockPrices.COMPANY: method set_Id should be 'public/protected virtual' or 'protected internal virtual'
StockPrices.COMPANY: method get_COMPANY_NAME should be 'public/protected virtual' or 'protected internal virtual'
StockPrices.COMPANY: method set_COMPANY_NAME should be 'public/protected virtual' or 'protected internal virtual'
StockPrices.COMPANY: method get_COMPANY_TICKER should be 'public/protected virtual' or 'protected internal virtual'
StockPrices.COMPANY: method set_COMPANY_TICKER should be 'public/protected virtual' or 'protected internal virtual'
StockPrices.COMPANY: method get_ASSET_TYPE_ID should be 'public/protected virtual' or 'protected internal virtual'
StockPrices.COMPANY: method set_ASSET_TYPE_ID should be 'public/protected virtual' or 'protected internal virtual'
StockPrices.COMPANY: method get_IS_ACTIVE should be 'public/protected virtual' or 'protected internal virtual'
StockPrices.COMPANY: method set_IS_ACTIVE should be 'public/protected virtual' or 'protected internal virtual'
StockPrices.COMPANY: field _Id should not be public nor internal
StockPrices.COMPANY: field _COMPANY_NAME should not be public nor internal
StockPrices.COMPANY: field _COMPANY_TICKER should not be public nor internal
StockPrices.COMPANY: field _ASSET_TYPE_ID should not be public nor internal
StockPrices.COMPANY: field _IS_ACTIVE should not be public nor internal"
This message provides a few clues. The messages seem to indicate that my class needs to use virtual properties (ala C#). I also assume this to mean that my F# syntax does not yield virtual properties.
So, I need to poke around a find how to create virtual properties in F#
This is what I came up with:
-----------------------------------------------------------------------------------------------
type COMPANY() = class
let mutable _Id : int = 0
let mutable _COMPANY_NAME : string = ""
let mutable _COMPANY_TICKER : string = ""
let mutable _ASSET_TYPE_ID : int = 0
let mutable _IS_ACTIVE : int = 0
abstract Id : int with get, set
default x.Id with get() = _Id and set(v) = _Id <- v
abstract COMPANY_NAME : string with get, set
default x.COMPANY_NAME with get() = _COMPANY_NAME and set(v) = _COMPANY_NAME <- v
abstract COMPANY_TICKER : string with get, set
default x.COMPANY_TICKER with get() = _COMPANY_TICKER and set(v) = _COMPANY_TICKER <- v
abstract ASSET_TYPE_ID : int with get, set
default x.ASSET_TYPE_ID with get() = _ASSET_TYPE_ID and set(v) = _ASSET_TYPE_ID <- v
abstract IS_ACTIVE : int with get, set
default x.IS_ACTIVE with get() = _IS_ACTIVE and set(v) = _IS_ACTIVE <- v
end
-----------------------------------------------------------------------------------------------
It is very similar to my class above, however, it uses the keyword 'abstract' to create an abstract property. The 'default' keyword (replacing the member keyword) then heads of the implementation of the property in the current class.
This is from MSDN:
"Properties can be abstract. As with methods, abstract just means that there is a virtual dispatch associated with the property. Abstract properties can be truly abstract, that is, without a definition in the same class. The class that contains such a property is therefore an abstract class. Alternatively, abstract can just mean that a property is virtual, and in that case, a definition must be present in the same class. Note that abstract properties must not be private, and if one accessor is abstract, the other must also be abstract."http://msdn.microsoft.com/en-us/library/dd483467(VS.100).aspx
If one were to refer to a POCO class in F#, this would probably be along the lines you would expect.
OK, let's give this puppy a twirl!
Kaboom!
I crash again on the same line as before.
This is my error:
NHibernate.InvalidProxyTypeException was unhandled
Message="The following types may not be used as proxies:
StockPrices.COMPANY: field _Id should not be public nor internal
StockPrices.COMPANY: field _COMPANY_NAME should not be public nor internal
StockPrices.COMPANY: field _COMPANY_TICKER should not be public nor internal
StockPrices.COMPANY: field _ASSET_TYPE_ID should not be public nor internal
StockPrices.COMPANY: field _IS_ACTIVE should not be public nor internal"
Shorter, but still a problem. At least I have gotten rid of the 'virtual property' errors and I am now left with a bunch of errors that seem to say that my private variable placeholders are illegal. I find this odd, as I do not get the same message with this type of syntax in VB:
-------------------------------------------------------------------------
Option Explicit On
Namespace StockPrices
Public Class COMPANY
Private _ID As Integer
Private _CompanyName As String
Private _CompanyTicker As String
Public Overridable Property Id() As Integer
Get
Id = _ID
End Get
Set(ByVal value As Integer)
_ID = value
End Set
End Property
Public Overridable Property COMPANY_NAME() As String
Get
COMPANY_NAME = _CompanyName
End Get
Set(ByVal value As String)
_CompanyName = value
End Set
End Property
Public Overridable Property COMPANY_TICKER() As String
Get
COMPANY_TICKER = _CompanyTicker
End Get
Set(ByVal value As String)
_CompanyTicker = value
End Set
End Property
End Class
End Namespace
-------------------------------------------------------------------------
The above outline for a class works fine with Fluent NHibernate.
What to do?
Well, I know my class would be OK if I could just get rid of the proxy errors. I mean these variables should be irrelevant, no?
So, I found a way to suppress them:
properties.Add("use_proxy_validator", "false")
I just need to add the above line to my properties collection. This kills the proxy validator.
I know this could have unknown repercussions, so if anyone knows a legitimate way around this problem, I would sure like to know.
Low and behold, this actually works.
I get exactly what I expect!
My output:
-------------------------------------------------------------------------
NHibernate: SELECT company0_.Id as Id0_0_, company0_.IS_ACTIVE as IS2_0_0_, company0_.ASSET_TYPE_ID as ASSET3_0_0_, company0_.COMPANY_TICKER as COMPANY4_0_0_, company0_.COMPANY_NAME as COMPANY5_0_0_ FROM [COMPANY] company0_ WHERE company0_.Id=@p0;@p0 = 100
Company Name: AT&T, Ticker: T
-------------------------------------------------------------------------
We are now good!