Given the following classes and interface I am wondering how JPa handles it:
public interface Operator{
public String getOperator();
}
Let's stay I then have two implementations of this class:
public class PlusOperation implements Operator, Serializable {
public String getOperator(){
return "+";
}
}
And:
public class MinusOperation implements Operator, Serializable {
public String getOperator(){
return "-";
}
}
There exists a class marked as #Entity which has a property Operator:
#Entity
public class Function {
#Id #GeneratedValue
private Long id;
private Operator operator;
// Other methods & properties omitted for clarity
}
In the Function class therefore, it could hold either a PlusOperation or MinusOperation and neither of these classes have been annotated with #Entity as they don't have any properties that require persisting but they each are different. How does JPA handle this? When persisting a Function object does it automatically (and 'behind the scenes') mark the operator property with the correct Operation implementation?
Just add a JPA AttributeConverter that stores the "operator" field as a String or Integer. That way it doesn't matter one iota whether this other type (which isn't an Entity) doesn't have any properties of its own. You converter is then responsible for deciding what is persisted, and how it is retrieved.
Related
I have a simple base class in which I want to have some common fields, like id etc. The base class is not an Entity by itself.
public class Base {
#Id
protected long id;
protected String someOtherCommonProperty;
}
And I have an entity class, extending the base class.
#Entity
public class Entity extends Base {
String name;
String address;
}
I would expect the entity class to inherit the fields from the base class, but what I get is
[ObjectBox] No #Id property found for 'Entity', add #Id on a not-null long property.
Is there any way to fix that, besides using interfaces and have a lot of duplicated code?
You can use the #BaseEntity annotation.
Have a look at the documentation: Objectbox - Entity Inheritence.
Shameless copy for future reference:
In addition to the #Entity annotation, we introduced a #BaseEntity annotation for base classes, which can be used instead of #Entity.
There three types of base classes, which are defined via annotations:
No annotation: The base class and its properties are not considered for persistence.
#BaseEntity: Properties are considered for persistence in sub classes, but the base class itself cannot be persisted.
#Entity: Properties are considered for persistence in sub classes, and the base class itself is a normally persisted entity.
Example:
// base class:
#BaseEntity
public abstract class Base {
#Id long id;
String baseString;
public Base() {
}
public Base(long id, String baseString) {
this.id = id;
this.baseString = baseString;
}
}
// sub class:
#Entity
public class Sub extends Base {
String subString;
public Sub() {
}
public Sub(long id, String baseString, String subString) {
super(id, baseString);
this.subString = subString;
}
}
I have 3 entities that have something in common.
#Entity
public class BaseEntity {
Date updatedAt;
}
#EntitySubclass
public class A extends BaseEntity {
String someData;
}
#EntitySubclass
public class B extends BaseEntity {
int someData;
}
#EntitySubclass
public class C extends BaseEntity {
boolean someData;
}
Can I make one query to create List<BaseEntity> or Query<BaseEntity>?
Supposedly something like this?
ofy().load().type(User.class).filter("updatedAt > ", someDate)
Actually, with Objectify I think you can. Here they give an example:
https://code.google.com/p/objectify-appengine/wiki/Entities#Polymorphism
I think the datastore can't do it natively, but Objectify will setup a structure for you that allows polymorphism anyway.
The other answer is not strictly correct. With Objectify, you can query by kind on a superclass and it will seamlessly query all applicable datastore entities which match the inheriting #Entity annotated classes.
I have an abstract class annotated as #MappedSuperclass. This class defines attributes common to all JPA classes such as Id.
I would like to override Id attribute mapping defined in the abstract super class and assign a sequence generator. Is it possible to override Id attribute mapping and assign a different sequence generator in JPA 2.x?
One thing that pops into my head is to use two base classes; one without the ID property and one that explicitly adds the ID property. Then you have freedom if you extend the one with ID or the one without ID so you can provide one specifically in the entity. Code skeleton without annotations:
public abstract class _Base {
// common properties here
}
public abstract class _BaseWithId extends _Base {
private Long id;
}
public class MyEntity1 extends _BaseWithId {
}
public class MyEntity2 extends _Base {
private Long id;
}
I am trying to use an inner class as embeddable to represent some complicated properties of the outer class. When I store this, there is no information from the inner class in the database schema generated by eclipselink.
Does what I'm trying to do seem like a good idea? Why doesn't eclipselink seem to recognize them #Basic attribute on the getRate() in Attributes?
Some other info: Measure must be instantiated using a factory which is provided to the constructor of Person, so I don't even know how I'm going to be able to use this at all. It seems more and more likely that I'll have to make a separate class just to store the state of Person in simple terms (like doubles, not Measures) and use those to create the real Person-type objects, but that has very sad implications for the rest of my application.
#Entity
public static class Person {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Transient
public Measure<Double, CleanupRate> rate;
#Embedded
private Attributes attributes;
#Embeddable
public static class Attributes {
#Transient
private Person person;
public Attributes() {
}
public Attributes(Person person) {
this.person = person;
}
#Basic
public double getRate() {
return person.rate.getInternalValue();
}
public void setRate(double value) {
person.rate.setInternalValue(value);
}
}
public Person() {
rate = udm.getMeasureFactory().createMeasure(0.0, CleanupRate.class);
attributes = new Attributes(this);
}
public void setRate(double rate) {
this.rate.setValue(rate);
}
}
Edit:
In order to inject the measure dependency into my objects when they are retrieved from storage, I've added an interface which injects the dependency and used it in my DAO. Since the DAO can be injected, I can propagate the dependency down to the retrieved objects. I got the idea from a blog.
private <T extends UomInjectable> List<T> //
getListOfUomInjectableType(final Class<T> klass) {
List<T> result = getListOfType(klass);
for (UomInjectable injectable : result) {
injectable.injectUomFactory(udm);
}
return result;
}
It is using the access type from the Person class, which is set to field, and so not seeing the annotation at the property level.
You will need to change the access type using Access(PROPERTY) on the embeddable class, and should remove the #Transient annotation on the person attribute.
I think in general you're going to be in trouble having Entities (Embeddable or otherwise) that need constructors with arguments. I'm not sure how that might be related to your schema generation issue, but I think this will be a problem trying to persist/retrieve these objects.
As you hinted, JPA requires all entity types to have a no-argument constructor. While your Attributes class has one, it leaves the 'person' field as null which will fairly quickly result in NPE's. Same with the Person constructor (maybe you left out the one that passes in 'udm' from the sample code?).
The set the Person for the Attributes, just use property access in Person and set it in your setAttributes method.
See,
http://en.wikibooks.org/wiki/Java_Persistence/Embeddables#Relationships
Is it possible to use an enum as a discriminator value when using SINGLE_TABLE inheritance strategy?
If what you are trying to achieve is to not to duplicate the discriminator values, there is a simple workaround.
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="FREQUENCY",
discriminatorType=DiscriminatorType.STRING
)
public abstract class Event {
}
#Entity
#DiscriminatorValue(value=Frequency.Values.WEEKLY)
public class WeeklyEvent extends Event {
…
}
public enum Frequency {
DAILY(Values.DAILY),
WEEKLY(Values.WEEKLY),
MONTHLY(Values.MONTHLY);
private String value;
…
public static class Values {
public static final String DAILY = "D";
public static final String WEEKLY = "W";
public static final String MONTHLY = "M";
}
}
Nothing to do with Hibernate/JPA really, but better than having to maintain the values in multiple places.
I just wanted to improve the great answer of #asa about the workaround. Usually, we often like to use the discriminator column as an attribute of the abstract class, and mapped with an enum of course. We can still use the solution mentioned above and force some consistencies between enum names (used to map the column) and String values (used as discrimnator values). Here is my suggestion:
public enum ELanguage {
JAVA(Values.JAVA), GROOVY(Values.GROOVY);
private ELanguage (String val) {
// force equality between name of enum instance, and value of constant
if (!this.name().equals(val))
throw new IllegalArgumentException("Incorrect use of ELanguage");
}
public static class Values {
public static final String JAVA= "JAVA";
public static final String GROOVY= "GROOVY";
}
}
And for the entities, here is the code:
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="LANGUAGE_TYPE", discriminatorType=DiscriminatorType.STRING)
public abstract class Snippet {
// update/insert is managed by discriminator mechanics
#Column(name = "LANGUAGE_TYPE", nullable = false, insertable = false, updatable = false)
#Enumerated(EnumType.STRING)
public ELanguage languageType
}
#Entity
#DiscriminatorValue(value=ELanguage.Values.JAVA)
public class JavaSnippet extends Snippet {
…
}
Still not perfect, but a little bit better, I think.
No, unfortunately you can't.
If you try to use an enum as discriminator value, you'll get a Type Mismatch exception ("cannot convert from MyEnum to String"), as the only discriminator types allowed are String, Char and Integer.
Next, I tried using an enum's name and ordinal combined with DiscriminatorType.STRING and DiscriminatorType.INTEGER, respectively. But this didn't work either, as the #DiscriminatorValue annotation (as any other) requires a constant expression:
This doesn't work:
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="FREQUENCY",
discriminatorType=DiscriminatorType.STRING
)
public abstract class Event {}
#Entity
#DiscriminatorValue(value=Frequency.WEEKLY.name())
public class WeeklyEvent extends Event {
// Exception: The value for annotation attribute DiscriminatorValue.value must be a constant expression
}
Doesn't work either:
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="FREQUENCY",
discriminatorType=DiscriminatorType.INTEGER
)
public abstract class Event {}
#Entity
#DiscriminatorValue(value=Frequency.WEEKLY.ordinal())
public class WeeklyEvent extends Event {
// Exception: The value for annotation attribute DiscriminatorValue.value must be a constant expression
}
I would suggest to invert the relationship: define the discriminator value as a constant in the entity, then wrap it in the enum:
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(
name = "FIELD_TYPE",
discriminatorType = DiscriminatorType.STRING
)
public class Shape {}
#Entity
#DiscriminatorValue(Square.DISCRIMINATOR_VALUE)
public class Square extends Shape {
public static final String DISCRIMINATOR_VALUE = "SQUARE";
}
#Entity
#DiscriminatorValue(Circle.DISCRIMINATOR_VALUE)
public class Circle extends Shape {
public static final String DISCRIMINATOR_VALUE = "CIRCLE";
}
#AllArgsConstructor
public enum FieldType {
SHAPE(Shape.DISCRIMINATOR_VALUE),
CIRCLE(Circle.DISCRIMINATOR_VALUE);
#Getter
private final String discriminatorValue;
}
Apart from eliminating duplication, this code is also less tightly coupled: entity classes don't depend on enum values and can be added without having to change other code; while the enum can "enumerate" different classes from different sources - depending on the context where it is used.
To my knowledge, this is not possible with annotations:
discriminator value must be of type String
discriminator value must be a compile-time-constant, i.e. return values from methods on enums are not allowed.
yup ,when you define discriminator the annotation's option are name and discrimatorType
#DiscriminatorColumn (name="MYDISCRIMINATOR", discriminatorType= DiscriminatorType.INTEGER)
of which DiscriminatorType can only be:
DiscriminatorType.STRING
DiscriminatorType.CHAR
DiscriminatorType.INTEGER
unfortunate I didn't see this yesterday but well. That's the way it is
You can use DiscriminatorType.INTEGER, and map each subclass with #DiscriminatorValue("X"), where X must be the ordinal value of the enum (0,1,2,3...).
It must be the value as a constant String. You can't use YourEnum.SOME_VALUE.ordinal(), because annotation attribute values must be constants. Yes, it is tedious. Yes, it is error-prone. But it works.