MongoDB LINQ提供程序对称为“id”的字段的奇怪行为

时间:2012-12-13 11:54:15

标签: linq mongodb mongodb-.net-driver

以下是Mongo LINQ提供程序失败的JSON文档:

{"results":
     {"text":"@twitterapi  http://tinyurl.com/ctrefg",
     "to_user_id":396524,
     "to_user":"TwitterAPI",
     "from_user":"jkoum",
     "metadata":
     {
      "result_type":"popular",
      "recent_retweets": 109
     },
     "id":1478555574, 
     "from_user_id":1833773,
     "iso_language_code":"nl",
     "source":"<a href=\"http://twitter.com/\">twitter<\/a>",
     "profile_image_url":"http://s3.amazonaws.com/twitter_production/profile_images/118412707/2522215727_a5f07da155_b_normal.jpg",
     "created_at":"Wed, 08 Apr 2009 19:22:10 +0000",
     "since_id":0,
     "max_id":1480307926,
     "refresh_url":"?since_id=1480307926&q=%40twitterapi",
     "results_per_page":15,
     "next_page":"?page=2&max_id=1480307926&q=%40twitterapi",
     "completed_in":0.031704,
     "page":1,
     "query":"%40twitterapi"}
}

注意“id”字段。以下是相关的C#实体定义:

class Twitter
{
    [BsonId]
    public ObjectId Id { get; set; }
    public Result results { get; set; }
}

private class Result
{
    public string text { get; set; }
    public int to_user_id { get; set; }
    public string to_user { get; set; }
    public string from_user { get; set; }
    public Metadata metadata { get; set; }
    public int id { get; set; }
    public int from_user_id { get; set; }
    public string iso_language_code { get; set; }
    public string source { get; set; }
    public string profile_image_url { get; set; }
    public string created_at { get; set; }
    public int since_id { get; set; }
    public int max_id { get; set; }
    public string refresh_url { get; set; }
    public int results_per_page { get; set; }
    public string next_page { get; set; }
    public double completed_in { get; set; }
    public int page { get; set; }
    public string query { get; set; }
}

class Metadata
{
    public string result_type { get; set; }
    public int recent_retweets { get; set; }
}

如果我创建一个“Twitter”集合并保存上面的文档,那么当我使用Mongo LINQ提供程序查询它时,它会抛出一个FileFormatException异常: “元素'id'与Mongo.Context.Tests.NativeTests + Result”类的任何字段或属性都不匹配“

但是,有两种替代解决方法可以解决此问题:

  1. 重命名结果“id”字段,例如在JSON doc和Result类中“idd”。然后LINQ查询工作。
  2. 保留“id”字段,但另外在Result类中添加字段“Id”并使用属性[BsonId]标记它。现在Result类包含“Id”和“id”字段,但查询有效!
  3. 我使用Mongo API来查询集合,一切正常,所以我猜这肯定是MongoDB LINQ提供程序中的一个错误。嵌套JSON元素中的“id”不应该是保留的工作,不应该吗?

    更新:以下是本机API查询执行的结果:

    > db.Twitter.find().limit(1);
    
    { "_id" : ObjectId("50c9d3a4870f4f17e049332b"),
     "results" : { 
        "text" : "@twitterapi  http://tinyurl.com/ctrefg", 
        "to_user_id" : 396524, 
        "to_user" : "TwitterAPI", 
        "from_user" : "jkoum", 
        "metadata" : { "result_type" : "popular", "recent_retweets" : 109 }, 
        "id" : 1478555574, 
        "from_user_id" : 1833773, "
        iso_language_code" : "nl", 
        "source" : "<a href=\"http://twitter.com/\">twitter</a>", 
        "profile_image_url" : "http://s3.amazonaws.com/twitter_production/profile_images/118412707/2522215727_a5f07da155_b_normal.jpg", 
        "created_at" : "Wed, 08 Apr 2009 19:22:10 +0000", 
        "since_id" : 0, 
        "max_id" : 1480307926, 
        "refresh_url" : "?since_id=1480307926&q=%40twitterapi", "results_per_page" : 15,    "next_page" : "?page=2&max_id=1480307926&q=%40twitterapi", 
        "completed_in" : 0.031704, 
        "page" : 1, 
        "query" : "%40twitterapi" 
        } 
    }
    

2 个答案:

答案 0 :(得分:14)

MongoDB要求存储在数据库中的每个文档都有一个名为&#34; _id&#34;的字段(在根级别)。

C#驱动程序假定您班级中的任何字段都称为&#34; Id&#34;,&#34; id&#34;或&#34; _id&#34;意图映射到特殊的&#34; _id&#34;领域。这是一个可以覆盖的约定。 C#驱动程序并不知道您的Result类不打算用作集合的根文档,因此它会找到您的&#34; id&#34;字段并将其映射到&#34; _id&#34;在数据库中。

您可以覆盖此方法的一种方法是更改​​类中字段的名称(如您所发现的那样)。您还可以使用[BsonElement]属性将您的C#字段名称(例如&#34; idd&#34;)映射到数据库中实际使用的任何名称(例如&#34; id&#34; )。例如:

public class Result
{
    [BsonElement("id")]
    public int idd; // matches "id" in the database
    // other fields
}

另一种选择是覆盖找到&#34; Id&#34;类的成员,用于抑制Result类的C#驱动程序的默认行为。您可以通过为Result类注册新的ConventionProfile来完成此操作。例如:

var noIdConventions= new ConventionProfile();
noIdConventions.SetIdMemberConvention(new NamedIdMemberConvention()); // no names
BsonClassMap.RegisterConventions(noIdConventions, t => t == typeof(Result));

在映射Result类之前,必须确保在程序的早期执行此操作。

答案 1 :(得分:0)

问题是您的POCO与您的JSON不匹配

您的Twitter班级有一个ID和一个名为结果的班级 然而,你的JSON才有结果。这就是问题所在。

所以实际上,你绕过了Twitter类,只创建了Result的实例

您的JSON应该类似于:

{
  _id: ObjectId("50c9c8f3e0ae76405f7d2b5e"), 
  "results": { 
     "text":"@twitterapi  http://tinyurl.com/ctrefg",
     "to_user_id":396524,
     "to_user":"TwitterAPI",
     "from_user":"jkoum",
     "metadata":
     {
      "result_type":"popular",
      "recent_retweets": 109
     },
     "id":1478555574, 
     "from_user_id":1833773,
     "iso_language_code":"nl",
     "source":"<a href=\"http://twitter.com/\">twitter<\/a>",
     "profile_image_url":"http://s3.amazonaws.com/twitter_production/profile_images/118412707/2522215727_a5f07da155_b_normal.jpg",
     "created_at":"Wed, 08 Apr 2009 19:22:10 +0000",
     "since_id":0,
     "max_id":1480307926,
     "refresh_url":"?since_id=1480307926&q=%40twitterapi",
     "results_per_page":15,
     "next_page":"?page=2&max_id=1480307926&q=%40twitterapi",
     "completed_in":0.031704,
     "page":1,
     "query":"%40twitterapi"}
    }
}

修改

您的results实际上是一个嵌入式文档(目前是POCO模型),因此您还应该使用[BsonId]

标记Result.ID