Suppose that I have a simple Hibernate entity with auto-incremented id.
@Entity
@Table(name = "product")
public class Product {
@Id
@GeneratedValue(strategy = IDENTITY)
private Long id;
private String name;
}
Is it possible to declare id
as a type-safe variable? I could apply @EmbeddedId
like this.
@Entity
@Table(name = "product")
public class Product {
@EmbeddedId
private ProductId id;
private String name;
@Embeddable
public static class ProductId implements Serializable {
@GeneratedValue(strategy = IDENTITY)
private Long id;
public Long getId() {
return id;
}
}
}
It works with client-generated IDs, but not with database-generated ones.
Has anyone solved similar problem? What are the possible approaches?
@EmbeddedId
Works when you are using an identity provided by either, the user or the application but not by the persistence mechanism.
In other words you need to assign the id prior persisting the entity. There are several ways to do so:
@Embeddable
public class ProductId {
private String uuid;
//Entity requirement
protected ProductId() { }
private ProductId(final String uuid) {
this.uuid = uuid;
}
public static ProductId of(final String uuid) {
return new ProductId(uuid);
}
public static ProductId createProductId() {
// You can also prefix the UUID so a human can identify
// where this id comes from in case you have multiple ids
// based on UUID, like SupplierId
String uuid = "product-" + UUID.randomUUID().toString();
return new ProductId(uuid)
}
}
so you create a new product id or get a ProductId
from a raw (String
) id
@Entity
public class Product {
private ProductId id;
private String name;
//Entity requirement
protected Product() { }
public Product(final String name) {
this.id = createProductId();//static import allowing you to use a friendly language
this.name = name;
}
ProductId
: select product_seq.nextval as product_id from dual
Another alternative is for you to use that numeric sequence as a surrogate identity and your product id. Thus, the ORM can identify entities by the surrogate id and your domain can identify entities by the entity id, product id in your case. You'll end up with something like
@Entity
public class Product {
@Id
@GeneratedValue
private Long id;
private ProductId productId;
...
}
The most important part for you is to discover what makes your product unique. Then you can create a ProductId
that matches that concept or simply use a UUID generated by the application. It depends on your domain, perhaps the name? barcode? sku?
Just bear in mind that a UUID might repeat, it is very very very hard and unlikely but not impossible. So if you go with UUID make sure your table column is unique, so you don't repeat UUIDs
Glad you are using value objects as identifiers instead of primitive values, kudos!