This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

Bug 172072 - "Entity Classes from Database" generates inappropriate methods
Summary: "Entity Classes from Database" generates inappropriate methods
Status: RESOLVED WONTFIX
Alias: None
Product: db
Classification: Unclassified
Component: DB schema (show other bugs)
Version: 6.x
Hardware: All All
: P3 blocker (vote)
Assignee: matthias42
URL:
Keywords:
: 177448 (view as bug list)
Depends on:
Blocks: 177448
  Show dependency tree
 
Reported: 2009-09-12 00:32 UTC by err
Modified: 2015-03-07 17:13 UTC (History)
2 users (show)

See Also:
Issue Type: DEFECT
Exception Reporter:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description err 2009-09-12 00:32:10 UTC
In a class made by "entity class from database" there is

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "ID", nullable = false)
    private Integer id;

The following methods are also generated. But seems they are invalid for an auto generated field. It would be an error
for an application to use them.

    public Person(Integer id) {
        this.id = id;
    }

    public void setId(Integer id) {
        this.id = id;
    }
Comment 1 Sergey Petrov 2009-09-12 06:24:53 UTC
Is there any realm error if I'll use these methods?
Comment 2 err 2009-09-12 13:41:51 UTC
        em.getTransaction().begin();
        p1.setId(1000000);
        em.getTransaction().commit();
results in

Exception [EclipseLink-7251] (Eclipse Persistence Services - 2.0.0.v20090821-r4934):
org.eclipse.persistence.exceptions.ValidationException
Exception Description: The attribute [id] of class [org.metawb.astro.db.Person] is mapped to a primary key column in the
database. Updates are not allowed.
javax.persistence.RollbackException: Exception [EclipseLink-7251] (Eclipse Persistence Services -
2.0.0.v20090821-r4934): org.eclipse.persistence.exceptions.ValidationException
Exception Description: The attribute [id] of class [org.metawb.astro.db.Person] is mapped to a primary key column in the
database. Updates are not allowed.
        at
org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commitInternal(EntityTransactionImpl.java:102)
        at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:63)
        at org.metawb.astro.db.PersonTest.setUp(PersonTest.java:61)
Caused by: Exception [EclipseLink-7251] (Eclipse Persistence Services - 2.0.0.v20090821-r4934):
org.eclipse.persistence.exceptions.ValidationException
Exception Description: The attribute [id] of class [org.metawb.astro.db.Person] is mapped to a primary key column in the
database. Updates are not allowed.
        at org.eclipse.persistence.exceptions.ValidationException.primaryKeyUpdateDisallowed(ValidationException.java:2372)
        ......


and


        clearDb();

        assert em == null;
        getEm();
        em.getTransaction().begin();
        p1 = new Person(1000000);
        em.persist(p1);
        em.getTransaction().commit();

        em.getTransaction().begin();
        p1.setFirstName("Ernie");
        em.getTransaction().commit();
        relEm();

gives surprising results, notice that the "p1.setFirstName("Ernie");" is lost somewhere. In some ways it seems an
exception should be thrown.

ij> select * from person;
ID         |LAST_NAME  |FIRST_NAME |MIDDLE_NAME
-----------------------------------------------
21         |NULL       |NULL       |NULL

1 row selected


Finally, using the correct constructor
        p1 = new Person();
in the previous example gives the expected results

ij> select * from person;
ID         |LAST_NAME  |FIRST_NAME  |MIDDLE_NAME
------------------------------------------------
22         |NULL       |Ernie       |NULL

1 row selected

I would guess that there are cases where they could be used with em.merge if you knew the id. But these seem rare and
specialized cases that shouldn't be in the default classes (my opinion).
Comment 3 Sergey Petrov 2009-09-14 10:05:31 UTC
"Exception [EclipseLink-7251] (Eclipse Persistence Services - 2.0.0.v20090821-r4934):
org.eclipse.persistence.exceptions.ValidationException
Exception Description: The attribute [id] of class [org.metawb.astro.db.Person] is mapped to a primary key column in the
database. Updates are not allowed."
it's look like an issue with attempt to update primary key and not the issue with autogenerated key. 
As for second sample with missed name it may be eclipselink/database issue or need additional investigation. Is there
any real restrictions from database side to specify id for new row instead of autogenerate?
Comment 4 err 2009-09-14 16:04:27 UTC
I understand why it is behaving this way, I believe the run-time behavior is correct.

The idea of this issue: the created methods and constructors that allow the programmer to attempt to set the "ID" are
invalid. They should not be auto created by the "entity from database" action because if they are used then errors or
unexpected things happen.

For this table in derby, the sql create is

    CREATE  TABLE ernie.person (
      id INT NOT NULL GENERATED ALWAYS AS IDENTITY ,
      last_name VARCHAR(45) ,
      first_name VARCHAR(45) ,
      middle_name VARCHAR(45) ,
      PRIMARY KEY (id) )
    ;

I am assuming there is enough info in the db schema to know that the column can not be written, that is is only autogen
(but I don't know for sure).
Comment 5 Sergey Petrov 2009-09-14 17:20:52 UTC
"if they are used then errors or
unexpected things happen." it may be only in case of inappropriate usage, otehrwise we can say no methods should be
generated for fields with "not null" constraint, as user can try to call setId(null) and persist (and it will cause
error) in case if it's not autogenerated field etc.
Comment 6 Sergey Petrov 2009-09-14 17:27:54 UTC
may be I need to try some use-cases first (with usage of constructor and setter in case of autogenerated pk)
Comment 7 Sergey Petrov 2009-09-14 17:39:51 UTC
for example I can create
create table greetings
	(i int generated by default as identity, ch char(50));
and PK will be autogenerated and derby will allow to specify pk anyway.
Comment 8 err 2009-09-14 18:06:37 UTC
>          generated by default as identity
> derby will allow specify pk

Yes, that is true. But in my example, I have

>          GENERATED ALWAYS AS IDENTITY
and you can *not* specify pk

If there is a standard way to determine that difference from the schema (or however the action works) then it seems the
second case should not have the methods/constructors that allow the pk to be set.

I don't think this is a serious problem, it is just that the class has confusing and misleading methods.

Consider

    CREATE  TABLE ernie.eventType (
      id INT NOT NULL GENERATED ALWAYS AS IDENTITY ,
      name VARCHAR(45) NOT NULL ,
      PRIMARY KEY (id) )

The only generated constructor to set the name is

    public Eventtype(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

but this is misleading, what I really want

    public Eventtype(String name) {
        this.name = name;
    }
Comment 9 Sergey Petrov 2009-09-21 11:45:52 UTC
yes, looks reasonable to generate Eventtype(String name), but also should be not problem with call 'new Eventtype(null,
name)'. as it's not serious problem and mostly usability issue, it may more like enhancement request for better support
for 'GENERATED ALWAYS AS IDENTITY' keys.
Comment 10 Sergey Petrov 2009-09-29 16:18:22 UTC
I don't see appropriate api in org.netbeans.modules.dbschema.ColumnElement, pass for evaluation.
feel free to pass back and file separate issue if it will be more appropriate.
Comment 11 Sergey Petrov 2009-09-29 16:22:57 UTC
I mean api to get if it's ALWAYS or DEFAULT auto-increment.
Comment 12 Sergey Petrov 2011-10-11 15:29:11 UTC
*** Bug 177448 has been marked as a duplicate of this bug. ***
Comment 13 matthias42 2015-02-08 20:18:35 UTC
Removed 154413 - persistence generation still uses dbschema ...

I'm inclined to close this as won't fix. Reasoning:

DBs have a different approaches to generated keys - I checked:

- Derby: integer GENERATED ALWAYS AS IDENTITY
  => not insertable, not updateable

- Informix: serial
  => insertable, not updateable

- MySQL: integer primary key auto_increment
  => insertable, updateable


So what would be appropriate? I see three possible approaches: 

Check based on DBMS - this does not scale (the jdbc driver does expose generated column, but whether that is reliable I would doubt it). While this would be correctly done in the dbschema/db.metadata modules. I would argue, that this defeates the purpose of JPA.

Always generate the setter to support DBs allowing INSERT/UPDATE. Drawback: You violate DBs that don't support parts of the set.

Don't generate setters. Drawback: You take away the option to set the IDs were possible.

My take: Its the responsibility of the developer to use/not use the feature, that the entity provides. The developer always has to be careful when setting IDs - he could check the underlying DB at runtime or add appropriate error handling.
Comment 14 matthias42 2015-03-07 17:13:01 UTC
Ok - I gave it another thought and won't fix this. The argument in comment 13 stands and reading the docs for oracle db 12c both cases (update+not updateable) are appliable to oracle.