简体   繁体   中英

Using NoRM to access MongoDB from F#

Testing out NoRM https://github.com/atheken/NoRM from F# and trying to find a nice way to use it. Here is the basic C#:

class products
{
    public ObjectId _id { get; set; }
    public string name { get; set; }
}

using (var c = Mongo.Create("mongodb://127.0.0.1:27017/test"))
{
    var col = c.GetCollection<products>();
    var res = col.Find();
    Console.WriteLine(res.Count().ToString());
}

This works OK but here is how I access it from F#:

type products() = 
    inherit System.Object()

    let mutable id = new ObjectId()
    let mutable _name = ""

    member x._id with get() = id and set(v) = id <- v
    member x.name with get() = _name and set(v) = _name <- v

Is there an easier way to create a class or type to pass to a generic method?

Here is how it is called:

use db = Mongo.Create("mongodb://127.0.0.1:27017/test")
let col = db.GetCollection<products>()
let count = col.Find() |> Seq.length
printfn "%d" count

Have you tried a record type?

type products = {
    mutable _id : ObjectId
    mutable name : string
    }

I don't know if it works, but records are often good when you just need a class that is basically 'a set of fields'.

Just out of curiosity, you can try adding a parameter-less constructor to a record. This is definitely a hack - in fact, it is using a bug in the F# compiler - but it may work:

type Products = 
  { mutable _id : ObjectId
    mutable name : string }
  // Horrible hack: Add member that looks like constructor 
  member x.``.ctor``() = ()

The member declaration adds a member with a special .NET name that is used for constructors, so .NET thinks it is a constructor. I'd be very careful about using this, but it may work in your scenario, because the member appears as a constructor via Reflection.

If this is the only way to get succinct type declaration that works with libraries like MongoDB, then it will hopefuly motivate the F# team to solve the problem in the future version of the language (eg I could easily imagine some special attribute that would force F# compiler to add parameterless constructor).

Here is a pretty light way to define a class close to your C# definition: it has a default constructor but uses public fields instead of getters and setters which might be a problem (I don't know).

type products =
    val mutable _id: ObjectId
    val mutable name: string
    new() = {_id = ObjectId() ; name = ""}

or, if you can use default values for your fields (in this case, all null):

type products() =
    [<DefaultValue>] val mutable _id: ObjectId
    [<DefaultValue>] val mutable name: string

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM