【问题标题】:Using NoRM to access MongoDB from F#使用 NoRM 从 F# 访问 MongoDB
【发布时间】:2010-11-29 08:11:56
【问题描述】:

从 F# 中测试 NoRM https://github.com/atheken/NoRM 并尝试找到一种使用它的好方法。这是基本的 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());
}

这工作正常,但这是我从 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

有没有更简单的方法来创建类或类型以传递给泛型方法?

它是这样称呼的:

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

【问题讨论】:

  • RavenDB 与 F# 配合得很好,他们的源代码树中有一些 F# 示例:github.com/ravendb/ravendb/tree/master/Samples/…
  • 看起来很有趣,但是“如果你的项目是开源的,你可以免费使用 Raven。如果你想使用 Raven 来构建商业软件,你必须购买商业许可证。” ravendb.net/licensing
  • 值得注意的是,RavenDB 现在有一个可以商业使用的免费许可证。但是它限制了可用内核的数量。见这里:ravendb.net/buy

标签: f# mongodb norm


【解决方案1】:

您尝试过记录类型吗?

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

我不知道它是否有效,但是当您只需要一个基本上是“一组字段”的类时,记录通常很好。

【讨论】:

  • 我先尝试了这个,但 NoRM 驱动程序抛出异常“没有为此对象定义无参数构造函数。”
  • mongodb-csharp 有同样的问题,他们使用 Activator.CreateInstance(ClassType, true);使用记录时抛出上述异常
【解决方案2】:

出于好奇,您可以尝试向记录添加无参数构造函数。这绝对是一个 hack - 事实上,它使用了 F# 编译器中的一个错误 - 但它可能会起作用:

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

member 声明添加了一个具有特殊 .NET 名称的成员,用于构造函数,因此 .NET 认为它是构造函数。我会非常小心地使用它,但它可能适用于您的场景,因为该成员通过反射显示为构造函数。

如果这是获得与 MongoDB 等库一起使用的简洁类型声明的唯一方法,那么它有望激励 F# 团队在该语言的未来版本中解决问题(例如,我可以很容易地想象一些特殊属性会强制 F# 编译器添加无参数构造函数)。

【讨论】:

  • 哇,太疯狂了,我环顾四周,看到很多问题都在问是否有可能有一个记录类型的无参数构造函数,所有人都说这是不可能的......
  • 但是你知道,我想我宁愿在记录引用类型的默认构造函数之前看到为普通引用类型实现的自动属性。确实,尽管有各种各样的方法可以简洁地定义类和结构,但我发现没有任何一种方法是足够的,而且它总是需要最冗长的方法来完成工作。我真的很想看到一种一致的单一方法来创建引用和结构类型,并在这些范围内实现简洁的功能。
  • 好吧,它不起作用。在反射器中查看 .ctor() 方法已创建,但 Activator.CreateInstance(t, false) 仍然抛出异常“没有为此对象定义无参数构造函数”。我已经在一个小型测试应用程序甚至 t.GetConstructor(new Type[] { });返回空值。但是,如果我将产品改回一个类(不是记录),那么它可以正常工作。 Reflector 建议主要区别在于记录是密封的,为什么它不起作用?
  • 啊哈,作为类的产品是“.method public specialname rtspecialname instance void .ctor() cil managed”,但作为记录的产品(带有 hack)是“.method public instance void .ctor() cil托管”,所以我猜 Activator.CreateInstance 正在寻找“特殊名称”?
  • 那么根据 ECMA-335 的第 10.5.1 节“实例构造函数应该是一个实例(不是静态或虚拟)方法,它应该被命名为 .ctor,并标记为实例、rtspecialname 和 specialname ”。我希望能够进一步调试并确切了解 CreateInstance 正在做什么......但看起来你的 hack 将无法工作,除非你也可以让编译器发出“rtsspecialname”和“specialname”。
【解决方案3】:

这是定义一个接近 C# 定义的类的一种非常简单的方法:它有一个默认构造函数,但使用公共字段而不是 getter 和 setter,这可能是个问题(我不知道)。

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

或者,如果您可以为您的字段使用默认值(在这种情况下,全部为空):

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

【讨论】:

  • 简洁又回来了!不幸的是,在 NoRM 中,它似乎正在寻找一个属性,但 _id 和 name 被编译为字段。不过,这确实适用于 mongodb-csharp。
  • :) 我害怕那个;当这些框架没有将公共领域与吸气剂平等对待时,我总是很恼火,支持两者不应该付出太多额外的努力,而且我认为没有任何哲学上的理由不这样做。也许您可以向 NoRM 提出功能请求,因为他们声称可以接受(您可以指出他们的竞争对手支持这一点)。
  • 我给出这个作为答案是因为这是我所要求的,即使没有后派对
  • 值得补充的是,在 MVC 中使用 DataAnnotations 似乎只适用于属性而不是字段。
猜你喜欢
  • 2011-03-21
  • 1970-01-01
  • 1970-01-01
  • 2011-06-30
  • 1970-01-01
  • 2011-07-18
  • 2011-10-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多