Donald Wu
Donald Wu

Reputation: 127

Hibernate one to zero or one mapping. Exception: attempted to assign id from null one-to-one property?

I do as @Tony answered in Hibernate one to zero or one mapping.

I have a class FileMeta.

@Entity
@Inheritance
@DiscriminatorColumn(name = "DISCRIMINATOR", discriminatorType = DiscriminatorType.STRING, length = 30)
@DiscriminatorValue("FileMeta")
public class FileMeta {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    protected long id;

    ...SOME ATTRIBUTES...

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "FK_GARBAGE")
    @NotFound(action = NotFoundAction.IGNORE)
    protected Garbage garbage;

    @Enumerated(EnumType.ORDINAL)
    private FileT type;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "FK_SHARE")
    @NotFound(action = NotFoundAction.IGNORE)
    private Share share;

    ...METHODS...
}

And a class Share.

@Entity
public class Share {
    @Id
    @GeneratedValue(generator = "shareForeignGenerator")
    @GenericGenerator(
            name = "shareForeignGenerator",
            strategy =  "foreign",
            parameters = @Parameter(name = "property", value = "fileMeta")
    )
    private Long id;

    ...SOME ATTRIBUTES...

    @OneToOne(mappedBy = "share")
    @PrimaryKeyJoinColumn
    @NotFound(action = NotFoundAction.IGNORE)
    private FileMeta fileMeta;

    ...METHODS...
}

And when I tried to fill my FileMeta with Share:

    Share share = new Share();
    share.setFileMeta(fileMeta);
    fileMeta.setShare(share);
    fileMetaRepository.save(fileMeta);

I received exception: attempted to assign id from null one-to-one property

I followed into Hibernate. And noticed that, in generator method, the associatedObject is not my given Share object at all, but a new Share object instantiated by a EventSource

In DefaultMergeEventListener.java,

    if ( copyCache.containsKey( entity ) ) {
        persister.setIdentifier( copyCache.get( entity ), id, source );
    }
    else {
        ( (MergeContext) copyCache ).put( entity, source.instantiate( persister, id ), true ); //before cascade!
    }

The copyCache sensed that entity (i.e my given Share object) is not in copyCache, and instantiated a new Share object, which doesn't have a FileMeta reference obviously.

I've completely confused.

Upvotes: 1

Views: 2816

Answers (1)

izogfif
izogfif

Reputation: 7495

The solution was mentioned in the comments to the question. It's given below for convenience.

You can use @OneToOne(optional = true) or simply @OneToOne since default value of optional is true.

If you want to enforce 1 to 1 relationship, specify @OneToOne(optional = false).

Upvotes: 2

Related Questions