1

I have these entities

NormalizedChannelStock.java

@Entity
@Table(name = "stocks")
public class NormalizedChannelStock {

    @EmbeddedId
    private NormalizedChannelStockId id;

    @Column(name = "qty")
    private int qty;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "channel_id", insertable = false, updatable = false)
    private Channel channel;

    @Column(name = "created_at", updatable = false)
    private Timestamp createdAt;

    @Column(name = "updated_at", updatable = false)
    private Timestamp updatedAt;

    public NormalizedChannelStockId getId() {
        return id;
    }

    public void setId(NormalizedChannelStockId id) {
        this.id = id;
    }

    public int getQty() {
        return qty;
    }

    public void setQty(int qty) {
        this.qty = qty;
    }

    public Channel getChannel() {
        return channel;
    }

    public void setChannel(Channel channel) {
        this.channel = channel;
    }

    public Timestamp getCreatedAt() {
        return createdAt;
    }

    public Timestamp getUpdatedAt() {
        return updatedAt;
    }
}

NormalizedChannelStockId.java

@Embeddable
public class NormalizedChannelStockId implements Serializable {

    @Column(name = "channel_id")
    private Integer channelId;

    @Column(name = "sku")
    private String sku;

    public NormalizedChannelStockId() {
    }

    public NormalizedChannelStockId(Integer channelId, String sku) {
        this.channelId = channelId;
        this.sku = sku;
    }

    public Integer getChannelId() {
        return channelId;
    }

    public void setChannelId(Integer channelId) {
        this.channelId = channelId;
    }

    public String getSku() {
        return sku;
    }

    public void setSku(String sku) {
        this.sku = sku;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        NormalizedChannelStockId that = (NormalizedChannelStockId) o;
        return channelId.equals(that.channelId) &&
                sku.equals(that.sku);
    }

    @Override
    public int hashCode() {
        return Objects.hash(channelId, sku);
    }
}

Channel.java

@Entity
@Table(name = "channels")
public class Channel {

    @Id
    @Column(name = "channel_id")
    private int channelId;

    @Column(name = "channel_name")
    private String channelName;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "store_id", insertable = false, updatable = false)
    private Store store;

    public int getChannelId() {
        return channelId;
    }

    public void setChannelId(int channelId) {
        this.channelId = channelId;
    }

    public String getChannelName() {
        return channelName;
    }

    public void setChannelName(String channelName) {
        this.channelName = channelName;
    }

    public Store getStore() {
        return store;
    }

    public void setStore(Store store) {
        this.store = store;
    }
}

The problem I'm facing is when I call

List<NormalizedChannelStock> entitiesToSave = ...
List<NormalizedChannelStock> savedEntities = normalizedChannelStockService.saveAll(entitiesToSave);

The returned entities in savedEntities have their Channel inner objects set to null, as well as their created_at and updated_at as shown

struct

Is this normal behaviour? When I run a findAllById on the Repository, the Channels inside the Entities are loaded lazily properly, so I believe the entities are properly mapped in code. The problem is after I save them. Does JPA not reload the entity after saving it?

Iwo Kucharski
  • 3,735
  • 3
  • 50
  • 66
MorganGlam
  • 129
  • 2
  • 11

1 Answers1

1

As you stated in the comments you did not set those values before saving.

JPA does not load them for you. JPA pretty much doesn't load anything upon saving except the id if it is generated by the database.

A more common case of the same problem/limitation/misconceptions are bidirectional relationships: JPA pretty much ignores the not owning side and the developer has to make sure that both sides are in sync at all times.

You would have to refresh the entity yourself. Note that just loading it in the same transaction would have no effect because it would come from the 1st level cache and would be exactly the same instance.

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
  • Would it be OK to manually refresh the entity after saving it? Say in the @Service layer, in the `save()` method, I'd call `loadById(entity)` after saving and then return the entity? – MorganGlam Apr 30 '20 at 15:30
  • Thank you. I accepted your answer and I implemented the answer here https://stackoverflow.com/a/48878923/10587134 for a working solution. – MorganGlam May 01 '20 at 01:51