简体   繁体   English

Grails MongoDB插件如何处理多态?

[英]How does Grails MongoDB plugin handle polymorphism?

I have an object like the following: 我有一个类似以下的对象:

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

    String email
    List<Profile> profiles;
}

interface Profile {
}

class Profile1 implements Profile {
}

class Profile2 implements Profile {
}

If I add the concrete classes Profile1 or Profile2 to the User object and save it to the database it throws an exception when reading that object back out of MongoDB. 如果我将具体的类Profile1或Profile2添加到User对象并将其保存到数据库,则从MongoDB中读回该对象时会引发异常。 I don't see any information being saved to the DB to identify which type of object it should instantiate in this situation. 在这种情况下,我看不到任何信息会保存到数据库中以标识应实例化的对象类型。 And there is exactly ZERO documentation about how this case is handled. 确切地有关于该案件如何处理的零文档。 Other frameworks have mechanisms for handling this so either Grails MongoDB is woefully broken, or this is just undocumented (again). 其他框架具有处理此问题的机制,因此Grails MongoDB被严重破坏了,或者(再次)未作记录。 So how do I fix this? 那么我该如何解决呢?

The exception is the following: 例外情况如下:

| 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     ''

Grails MongoDB is not at all broken and every use case might not get documented. Grails MongoDB完全没有损坏,每个用例都可能没有记录在案。 :) :)
Your use case works fine as expected and successfully tested as shown below. 您的用例可以按预期工作,并且如下所示已成功测试。

// 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 
}

You can also find the above setup here . 您也可以在此处找到上述设置。

Note:- For simplistic usage Profile1 and Profile2 is designed alike. 注意:-为了简化用法, Profile1Profile2的设计相似。

The actual answer is that grails seems to handle classes but not interfaces which is truly bizarre because if you handle polymorphism for classes it's trivial to handle it for interfaces because you can handle it the same way. 实际的答案是,grails似乎处理类而不是接口,这确实是奇怪的,因为如果您为类处理多态,那么为接口处理它是微不足道的,因为您可以以相同的方式处理它。 But if you use classes for all reference types it will add a special '_class' property to mongodb and it will use that to instantiate the object of the actual reference the object pointed to when it was saved. 但是,如果您将类用于所有引用类型,它将在mongodb中添加一个特殊的'_class'属性,并将使用该属性实例化实际引用的对象(该对象在保存时指向该对象)。 Now how hard was that to explain in one paragraph rather than trolling through pages of source code and unit tests? 现在,要用一个段落解释而不是浏览源代码和单元测试页面有多难?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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