【问题标题】:How does Grails MongoDB plugin handle polymorphism?Grails MongoDB 插件如何处理多态性?
【发布时间】:2013-06-13 17:11:59
【问题描述】:

我有一个像下面这样的对象:

class User {
    static mapWith="mongo"
    static embedded = [ 'profiles' ]

    String email
    List<Profile> profiles;
}

interface Profile {
}

class Profile1 implements Profile {
}

class Profile2 implements Profile {
}

如果我将具体类 Profile1 或 Profile2 添加到 User 对象并将其保存到数据库中,则在从 MongoDB 中读取该对象时会引发异常。我没有看到任何信息被保存到数据库中以确定在这种情况下应该实例化哪种类型的对象。关于如何处理这种情况的文档完全为零。其他框架有处理这个问题的机制,所以要么 Grails MongoDB 被严重破坏,要么这只是没有记录(再次)。那么我该如何解决呢?

例外情况如下:

| Error 2013-06-12 18:48:00,390 [http-bio-8080-exec-5] ERROR errors.GrailsExceptionResolver  - InstantiationException occurred when processing request: [POST] /mpa/user/authenticate -parameters:

  email: carhubb@gmail.com
  password: ***
  com.mycompany.security.Profile. Stacktrace follows:
  Message: com.mycompany.security.Profile
  Line | Method
  ->>  342 | newInstance0                        in java.lang.Class
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
  |    310 | newInstance                         in     ''

【问题讨论】:

    标签: mongodb grails grails-orm polymorphic-associations


    【解决方案1】:

    Grails MongoDB 完全没有损坏,每个用例可能都没有记录。 :)
    您的用例按预期正常工作并成功测试,如下所示。

    // src/groovy
    interface Profile {
        Integer getDuration()
    }
    
    import org.bson.types.ObjectId
    class Profile1 implements Profile {
        ObjectId id
        String profileName
        String type
        Date effectiveStartDate
        Date effectiveEndDate
    
        Integer getDuration(){
            effectiveEndDate - effectiveStartDate
        }
    
        static mapWith = "mongo"
    }
    
    import org.bson.types.ObjectId
    class Profile2 implements Profile{
        ObjectId id
        String profileName
        String type
        Date effectiveStartDate
        Date effectiveEndDate
    
        static mapWith = "mongo"
    
        Integer getDuration(){
            effectiveEndDate - effectiveStartDate
        }
    }
    class User {
        ObjectId id
    
        static mapWith = "mongo"
        static embedded = ['profiles']
    
        String email
        List<Profile> profiles
    }
    
    class UserController {
    
        def index() {
            def profile1 = new Profile1(type: 'Individual',
                                        profileName: 'IndividualProfile',
                                        effectiveStartDate: new Date(),
                                        effectiveEndDate: new Date() + 100) as Profile
            def profile2 = new Profile2(type: 'Company',
                                        profileName: 'CompanyProfile',
                                        effectiveStartDate: new Date(),
                                        effectiveEndDate: new Date() + 50) as Profile
    
            println profile1.duration //prints 100
            println profile2.duration //prints 50
    
            def user = new User(profiles: [profile1, profile2], email: 'abc@gmail.com').save(flush: true)
    
            render user as JSON
        }
    }
    
    //db.user.find()
    { 
        "_id" : ObjectId("51ba8d55892cb98368b2f1e5"), 
        "email" : "abc@gmail.com", 
        "profiles" : [{   
                "effectiveEndDate" : ISODate("2013-09-22T03:26:13.396Z"),   
                "effectiveStartDate" : ISODate("2013-06-14T03:26:13.396Z"),   
                "profileName" : "IndividualProfile",    
                "type" : "Individual" 
            },
            {   
                "effectiveEndDate" : ISODate("2013-08-03T03:26:13.423Z"),       
                "effectiveStartDate" : ISODate("2013-06-14T03:26:13.423Z"),   
                "profileName" : "CompanyProfile",
                "type" : "Company" 
            } 
        ], 
        "version" : 0 
    }
    

    你也可以找到上面的设置here

    注意:- 为简单起见,Profile1Profile2 设计相同。

    【讨论】:

    • mongodb如何知道根据type字段实例化Profile1 vs Profile2?这是否记录了那是什么行为?是不是被赋予了特殊意义的魔法场名?如果 type 是自动填写的(而不是强迫用户填写)不是更好吗?我浪费了很多时间试图找到任何人谈论这个,但什么都没有。那里的大多数信息似乎只是令人困惑,是否支持。 Grails 在文档部门非常令人失望(并且单元测试不是文档)。
    • 为什么mongodb 需要知道要实例化哪个 Profile?您的应用程序必须处理它。能否提供Profile1Profile2的接口和实现的详细设计?此外,我们需要走出waterfall 的世界,努力应对Agile。 TDD 使将单元测试用例视为文档变得更加容易和有效。如果没有人谈论这个问题,那么在 github 中挖掘源代码并尝试跟踪问题(如果有)。开源软件的驱动因素是来自用户的贡献。
    • 很好,我的应用程序必须如何处理实例化它?糟糕的文档是敏捷或瀑布中的糟糕文档。它与过程无关。我正在研究源代码,但这比快速阅读文档需要更多的时间和参与。另外,主要针对文档而非单元测试进行优化的搜索引擎对源代码的索引不是很好。当我搜索这些东西时,会出现零个单元测试。我们需要的是坚持实用性,而不是对流程陈词滥调。
    • @dmahapatro 如果 Profile1 和 Profile2 具有不同的属性,这会起作用吗? grails 会给我正确的配置文件类吗?就像它是休眠状态一样 - 使用休眠继承映射
    【解决方案2】:

    实际的答案是 grails 似乎只处理类而不是接口,这真的很奇怪,因为如果你处理类的多态性,那么处理接口的多态性是微不足道的,因为你可以用同样的方式处理它。但是,如果您为所有引用类型使用类,它将向 mongodb 添加一个特殊的“_class”属性,并将使用它来实例化对象在保存时指向的实际引用的对象。现在,用一段话来解释而不是翻阅源代码和单元测试页面有多难?

    【讨论】:

    • 你的界面在哪里?哪个目录?
    • 它在 src/groovy 下。您不能将接口放在 grails-app/domain 下,因为 grails 会尝试向其中添加方法。当它发生时也很难弄清楚。错误消息不清楚发生了什么。我想如果你不打算解决完整的问题文档很重要,但如果它只是开箱即用,我就不会那么热衷于文档了。真正的问题是 grails 在一些非常常见的情况下不能开箱即用,并且没有足够的文档记录我们可以快速解决它的地方。
    猜你喜欢
    • 1970-01-01
    • 2012-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-09
    相关资源
    最近更新 更多