Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NullPointerException thrown when updating an entity with multiple primary keys #3275

Open
lakxtxue opened this issue Nov 23, 2023 · 3 comments

Comments

@lakxtxue
Copy link

lakxtxue commented Nov 23, 2023

This exception occurs in both 12.16.1 and the latest 13.25.1 versions, I have not tried earlier versions.

Expected behavior

Expect the value of the col column to be updated to "success"

Actual behavior

java.lang.NullPointerException: Cannot invoke "io.ebean.bean.EntityBean._ebean_getField(int)" because "bean" is null

Steps to reproduce

Define the table under postgresql and add test records (the same problem occurs when testing under mysql)

DROP TABLE IF EXISTS "public"."test_multi_pk_update";
CREATE TABLE "public"."test_multi_pk_update" (
  "p1" varchar(32) COLLATE "pg_catalog"."default" NOT NULL,
  "p2" varchar(32) COLLATE "pg_catalog"."default" NOT NULL,
  "col" varchar(64) COLLATE "pg_catalog"."default"
);

INSERT INTO "public"."test_multi_pk_update" VALUES ('p1', 'p2', 'column_content');


ALTER TABLE "public"."test_multi_pk_update" ADD CONSTRAINT "test_id_class_pkey" PRIMARY KEY ("p1", "p2");

Define java beans

@Embeddable
public class TestMultiPkUpdateId {
    @AttributeOverride(name = "p1", column = @Column(name = "p1"))
    @Column(name = "p1")
    private String p1;

    @AttributeOverride(name = "p2", column = @Column(name = "p2"))
    @Column(name = "p2")
    private String p2;

    public String getP1() {
        return this.p1;
    }

    public void setP1(String p1) {
        this.p1 = p1;
    }

    public String getP2() {
        return this.p2;
    }

    public void setP2(String p2) {
        this.p2 = p2;
    }

    @Override
    public int hashCode() {
        int result = 17 * 31;
        result = 31 * result + Objects.hashCode(p1);
        result = 31 * result + Objects.hashCode(p2);
        return result;
    }

    @Override
    public boolean equals(Object that) {
        if (this == that) {
            return true;
        }
        if (!(that instanceof TestMultiPkUpdateId other)) {
            return false;
        }
        if (!Objects.equals(p1, other.p1)) return false;
        return Objects.equals(p2, other.p2);
    }
}
@Entity(name = "TestMultiPkUpdate")
@Table(name = "test_multi_pk_update")
@IdClass(TestMultiPkUpdateId.class)
public class TestMultiPkUpdate {
    @Id
    @Column(name = "p1")
    private String p1;

    @Id
    @Column(name = "p2")
    private String p2;

    @Column(name = "col", length = 64, nullable = true)
    private String col;

    public String getP1() {
        return this.p1;
    }

    public void setP1(String p1) {
        this.p1 = p1;
    }

    public String getP2() {
        return this.p2;
    }

    public void setP2(String p2) {
        this.p2 = p2;
    }

    public String getCol() {
        return this.col;
    }

    public void setCol(String col) {
        this.col = col;
    }
}

Execute the following code to reproduce the exception:

TestMultiPkUpdate testMultiPk = new TestMultiPkUpdate();
        testMultiPk.setP1("p1");
        testMultiPk.setP2("p2");
        testMultiPk.setCol("success");
        // Expect the value of the col column to be updated to "success". And the actual exception is thrown:
        // java.lang.NullPointerException: Cannot invoke "io.ebean.bean.EntityBean._ebean_getField(int)" because "bean" is null
        DB.update(testMultiPk);
  Caused by: java.lang.NullPointerException: Cannot invoke "io.ebean.bean.EntityBean._ebean_getField(int)" because "bean" is null
	at io.ebeaninternal.server.properties.EnhanceBeanPropertyAccess$Getter.get(EnhanceBeanPropertyAccess.java:57)
	at io.ebeaninternal.server.deploy.BeanProperty.getValue(BeanProperty.java:768)
@lakxtxue
Copy link
Author

Hi. I just want to say that this is an easily reproducible exception, and it is very common to use multiple columns as primary keys, I look forward to this exception being resolved. Or am I using it incorrectly? Please guide me past this blocker, thank you very much

@rPraml
Copy link
Contributor

rPraml commented Jan 16, 2024

Can you change your code to use embeddedId as composite PK? See https://github.com/ebean-orm/ebean/blob/master/ebean-test/src/test/java/org/tests/model/composite/ROrder.java for an example

@lakxtxue
Copy link
Author

Can you change your code to use embeddedId as composite PK? See https://github.com/ebean-orm/ebean/blob/master/ebean-test/src/test/java/org/tests/model/composite/ROrder.java for an example

Thanks for the guidance, I did successfully get the record updated using @EmbeddedId. I want to confirm that using @IdClass is not supported? Or is this a problem? Because I do tend to use @IdClass to map concatenated primary keys.

I noticed that ebean docs mentioned using @IdClass to map concatenated primary keys:
https://ebean.io/docs/interesting/embedded-id

Well I saw this location where there are unit tests using @IdClass:
https://github.com/ebean-orm/ebean/blob/master/tests/test-java16/src/test/java/org/example/records/RecordIdClassTest.java

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants