如何使用Hibernate作为持久性保存对象,使用Jackson使用外键?

时间:2015-10-23 06:13:10

标签: java spring hibernate jackson

如果之前已经回答过这个问题,我想提前道歉。

请注意,该项目使用的是Spring Boot,Jackson和Hibernate。

无论如何,我按Jasenko Hadziomeragic分叉了一个项目。我想知道他是如何在Jasenko的项目中保存一个对象的Product对象。在这个项目中,Product对象看起来像这样(请注意我删除了部分代码以专注于外键):

@JoinColumn(name = "member_id")
@NotNull
private Long member_id;

我可以使用此JSON保存新记录:

{
  "name" : "Product 2",
  "member_id" : "1"
}

这可行但是从我在互联网上搜索的内容来看,最好使用它:

public class Product {

@ManyToOne()
@JoinColumn(name="member_id")
private Member member;

/* A getter/setter for the memeber id*/
public Long getMember_id() {
    return this.member.getId();
}

public void setMember_id(Long member_id) {
    this.member.setId(member_id);
}
}

我尝试使用上面相同的json保存新记录,我收到此错误:

java.lang.NullPointerException: null
at com.jersey.representations.Product.setMember_id(Product.java:100)

这是指向我的github的链接,其中包含修改过的代码。

我还检查了这个与我关注的类似的SO question。但是首先它首先发送一个select查询来填充Member对象。但这意味着在保存记录之前,我必须请求另一个select语句。这有点开销,不是吗?

更新 我在构造函数中添加了这段代码:

public Product() {
    this.member = new Member();
}

我确实解决了我的问题,但这是处理我的问题的正确方法吗?

更新2

我想避免的是发送这个JSON:

[
    {
        "id": 1,
        "name": "Derp",
        "currency": "599",
        "regularPrice": 1203,
        "discountPrice": 59,
        "member": {
            "id": 1,
            "firstName": "Paul",
            "lastName": "Andrews",
            "email": "myemail@email.com"
        }
    },
    {
        "id": 2,
        "name": "Another product ",
       "currency": "909",
        "regularPrice": 1203,
        "discountPrice": 59,
        "member": {
            "id": 1,
            "firstName": "Paul",
            "lastName": "Andrews",
            "email": "myemail@email.com"
        }
    },
    {
        "id": 3,
        "name": "Another product 1",
        "currency": "909",
        "regularPrice": 1203,
        "discountPrice": 59,
        "member": {
            "id": 1,
            "firstName": "Paul",
            "lastName": "Andrews",
            "email": "myemail@email.com"
        }
    }
]

如您所见,该成员不断重复,而我可以发送memberId。

Another link to a similar question I posted

2 个答案:

答案 0 :(得分:0)

请尝试使用具有ModelProduct持久性的简单控制台应用程序来学习Hibernate。对@JoinColumn products@OneToMany mappedBy属性Member,您不需要Product。您可以将User称为Product,将UserFriend称为User。在每个config中,您需要拥有<connectionStrings> <add name="myConnectionString" connectionString="server=ServerAddress;database=myDb;uid=myUser;password=myPass;" /> </connectionStrings> 的外键 - 将产品添加到成员this way。对于实验,您可以使用thisthis

答案 1 :(得分:0)

好的,所以我终于让它工作了。我不知道在哪里查明,但我绝对可以说杰克逊问题不是JSON编组。

这是我的解决方案:

首先,我找不到解决方案,但要将其添加到具有外键的类中:

@Entity
public class Product {
    public Product() {
        this.member = new Member();
    }

    @ManyToOne()
    @JoinColumn(name="blargh")
    private Member member;
    /** Jackson can't instantiate and object automatically so you have to help it **/
    /** By creating the object right after Product is initialzed by some other code **/
    public Long getMobileNum() {
        return this.member.getMobileNum();
    }

    public void setMobileNum(Long mobileNum) {
        this.member.setMobileNum(mobileNum);
    }
}

下一步在其他类中查找Id注释。

@Entity
public class Member {

    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Id
    private Long mobileNum;
}

我故意将注释错误地证明了一点。在Product类中,将其链接到Member类的外键是mobileNum。如果使用@Id注释mobileNum或任何外键,Hibernate将正确绑定它并且不会在保存对象时出现任何问题。

但是如果外键没有用@Id,Hibernate注释(即使Jackson已经正确地将JSON映射到对象),它也不会正确绑定它,导致空值 Google搜索关键字:对象引用未保存的瞬态实例

在我看来,添加Cascade并不是一个好的解决方案,因为它只会在Member类中创建更多记录。如果记录已存在,它将继续创建EVEN! (尝试在mobileNum上设置一个唯一约束并删除@Id注释。

总的来说,本周Hibernate真的把我烧了。如果您是具有优化现有SQL经验并且只想将其转换为代码的开发人员,请远离Hibernate。使用MyBatis,即使它有很多样板,用手工创建SQL比用Hibernate更令人满意。