micronaut-projects / micronaut-data

Ahead of Time Data Repositories
Apache License 2.0
459 stars 196 forks source link

Unable to use @AutoPopulated UUID in a record #2968

Open burtbeckwith opened 3 weeks ago

burtbeckwith commented 3 weeks ago

Expected Behavior

I should be able to use @Id @AutoPopulated @Nullable UUID id as the primary key in a Record

Actual Behaviour

@Id @AutoPopulated @Nullable UUID id in a Record annotated with @MappedEntity fails to set a value for the id, causing inserts to fail

Steps To Reproduce

See the attached project, it's a simplified version of the app that's built as part of the HOL in https://github.com/oracle-livelabs/adb/tree/main/micronaut-oci-atp. Run PersistenceTest; testPetAsRecord() fails, but testPetAsClass() passes - it uses Pet2 which was converted from a Record to a regular class

Environment Information

No response

Example Application

No response

Version

4.4.2

burtbeckwith commented 3 weeks ago

issue2968.zip

dstepanov commented 3 weeks ago

Have you tried to have @GeneratedValue?

radovanradic commented 3 weeks ago

It works with @AutoPopulated and @GeneratedValue if record initializer is removed. That is confusing app from creating new record with generated id, it seems. Changing record to this

@Serdeable
@MappedEntity
public record Pet(
        // This class uses an autopopulated UUID for the primary key
        @Id @AutoPopulated @Nullable UUID id,
        String name,
        // A relation is defined between Pet and Owner
        @Relation(Relation.Kind.MANY_TO_ONE)
        Owner owner,
        // Optional columns can be defined by specifying Nullable
        @Nullable
        PetType type) {

    // Secondary record constructors make it easier to construct instances
    public Pet(String name, Owner owner) {
        this(name, owner, null);
    }

    public Pet(String name, Owner owner, PetType type) {
        this(null, name, owner, type == null ? PetType.DOG : type);
    }

    public enum PetType {
        DOG,
        CAT
    }
}

seems to be working.

graemerocher commented 3 weeks ago

note this is a regression as it used to work

radovanradic commented 3 weeks ago

Yes, in 3.10.0 it worked. This is the difference when record is used. This method in DefaultEntityEventContext

@Override
    public <P> void setProperty(BeanProperty<T, P> property, P newValue) {
        if (property.hasSetterOrConstructorArgument()) { // in 3.10.0 this returns true and in 4.4.2 false
            if (property.isReadOnly()) {
                this.entity = property.withValue(entity, newValue);
            } else {
                property.set(entity, newValue);
            }
        }
    }