I've been using Spring Data for saving entities to the mongo DB and my code at the moment looks like this:
I have a repo class:
public interface LogRepo extends MongoRepository<Log, String> {
}
and I have an Entity Log which looks like this:
#Document(
collection = "logs"
)
public class Log {
#Id
private String id;
private String jsonMessage;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getJsonMessage() {
return jsonMessage;
}
public void setJsonMessage(String jsonMessage) {
this.jsonMessage = jsonMessage;
}
}
and this work well for me, however this approach works only for the case if I want to save Log entities to "logs" collection. However it would be very nice for me to be able to save Log entity to different collections depending on the context. I mean it would be nice to define collection name in the runtime. Is it possible somehow?
Thanks, cheers
Try to use inheritance and define appropriate collection names in such way. May give you possibility to save in different collections but you will be still not able to specify dynamically collection names and resp. their amount at runtime.
#Document(
collection = "logs"
)
public class Log {
#Id
private String id;
private String jsonMessage;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getJsonMessage() {
return jsonMessage;
}
public void setJsonMessage(String jsonMessage) {
this.jsonMessage = jsonMessage;
}
}
#Document(
collection = "log_child"
)
public class LogChild extends Log{}
With the MongoOperations save method you can choose which class to use and
based on the class it will choose the appropriate collection.
#Document(collection = "collection_#{T(com.github.your_project.DBUtils).getCollectionName()}")
public Class Collection
You can change the name in real time using a static getter
#UtilityClass
public class DBUtils {
private String collectionName;
public String getCollectionName() {
return collectionName;
}
public void setCollectionName(String collectionName) {
DBUtils.collectionName = collectionName;
}
}
Related
I have an interface that defines a method that returns an instance of a helper class and I was wondering if there's a better way of going about what I'm trying to do.
For example, say I have a Tag class:
public class Tag {
private long id;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}
You can assign Tags to other objects.
The assignment is represented by TagAssign:
public abstract class TagAssign {
private Tag tag;
public Tag getTag() {
return tag;
}
public void setTag(Tag tag) {
this.tag = tag;
}
}
A new type of assignment will extend TagAssign and define what the Tag's being assigned to.
For example, a Tag assigned to a User would look like the following:
public class UserTag extends TagAssign {
private long id;
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}
An object that can have a tag assigned to it will implement the TagAssignable interface:
public interface TagAssignable {
public TagAssignableHelper getTagAssignableHelper();
}
TagAssignable defines a method that returns an instance of TagAssignableHelper.
At the moment, TagAssignableHelper just defines a method that assigns the Tag to the TagAssignable, returning a TagAssign.
public interface TagAssignableHelper<A extends TagAssignable, T extends TagAssign> {
public T assignTag(A assignable, Tag tag);
}
Here's what a User class that implements TagAssignable would look like:
public class User implements TagAssignable {
private long id;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
#Override
public UserTagAssignableHelper getTagAssignableHelper() {
return new UserTagAssignableHelper();
}
}
And UserTagAssignableHelper looks like:
public class UserTagAssignableHelper implements TagAssignableHelper<User, UserTag> {
#Override
public UserTag assignTag(User assignable, Tag tag) {
UserTag userTag = new UserTag();
userTag.setUser(assignable);
userTag.setTag(tag);
return userTag;
}
}
The code in use:
public class Main {
public static void main(String[] args) {
List<TagAssignable> assignables = new ArrayList<>();
assignables.add(new User());
Tag tag = new Tag();
List<TagAssign> assignments = new ArrayList<>();
for (TagAssignable assignable : assignables) {
TagAssign assignment = assignable.getTagAssignableHelper().assignTag(assignable, tag);
assignments.add(assignment);
}
}
}
I basically want each type of TagAssignable to define how it's used inside the framework. When a developer marks a class as TagAssignable, they have to define how the TagAssign class is created, because at some point in the framework it's going to try and do just that.
I'm trying to avoid doing something like this:
if(assignable instanceof User) {
User user = (User) assignable;
UserTag userTag = new UserTag();
userTag.setTag(tag);
userTag.setUser(user);
return userTag;
}
// followed by more ifs for each type of TagAssignable
I'm open to all feedback and suggestions.
I think introducing the TagAssign class hierarchy complicates your design. What I would try to achieve is to change the TagAssignable interface to only have Set<Tag> getTags(), add(Tag tag) and remove(Tag tag) tags. If you want to achieve immutability of objects with tags, you could change the interface to have with(Tag tag) and without(Tag tag) methods that return mutated instances. This would remove the need for separate assignment classes and their corresponding helpers.
I have the following class structure:
public abstract class Creature{
private String name;
//strategy pattern composition
private SkillInterface skill;
}
public interface SkillInterface {
void attack();
}
public class NoSkill implements SkillInterface {
#Override
public void attack() {
//statements
}
}
My goal is to persist Creature objects at one table in database. Subclasses of SkillInterface are without any fields. As they determine the behaviour, I want to convert selected SkillInterface class name to a String, as I only need to persist the classname of the current skill strategy of creature, with a String like skill.getClass().getSimpleName(). I tried to implement it with #Converter annotation, using AttributeConverter class to convert SkillInterface to String and save, but always had mapping exceptions. I want to be able to save it as String and retrieve as SkillInterface object.
But how can I implement it with Hibernate? Or do I have a design mistake?
Ok looks like I have found a basic solution that can be used to persist Strategy Pattern interfaces implementations. I used a #Converter annotation and a AttributeConverter class to convert strategy class names to column while saving to database and cast the retrieved String back to strategy class as following:
#Entity
public class Creature {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Convert(converter = SkillConverter.class)
private SkillInterface skill;
}
public class SkillConverter implements AttributeConverter<SkillInterface,String> {
#Override
public String convertToDatabaseColumn(SkillInterface skill) {
return skill.getClass().getSimpleName().toLowerCase();
}
#Override
public SkillInterface convertToEntityAttribute(String dbData) {
//works as a factory
if (dbData.equals("noskill")) {
return new NoSkill();
} else if (dbData.equals("axe")) {
return new Axe();
}
return null;
}
}
public interface SkillInterface {
public String getSkill();
void attack();
}
public class NoSkill implements SkillInterface{
public String getSkill() {
return getClass().getSimpleName();
}
#Override
public void attack() {
//strategy statements
}
}
You can use a proxy field to this for you like below:
abstract class Creature {
#Column
private String name;
// strategy pattern composition
private SkillInterface skill;
#Column
private String skillName;
public String getSkillName() {
return skill.getClass().getSimpleName();
}
public void setSkillName(String skillName) {
//ignore
}
}
As the question says, I would like to know the easiest way to perform Data Binding to regular (non JavaFX) properties of JPA entities.
I was thinking there is probably some way to use the same binding functions if you make your entity class implement some interface for change listeners or something of the sort.
Here is an example of a JPA entity with property changed listeners.
#Entity
public class Ticket {
#Id
#GeneratedValue()
private int id;
#ManyToOne()
private EntryGate entryGate;
#ManyToOne()
private ExitGate exitGate;
#Transient
private PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);
public Ticket() {
}
public Ticket(EntryGate owner) {
this();
this.entryGate = owner;
}
public void addListener(PropertyChangeListener listener) {
changeSupport.addPropertyChangeListener(listener);
}
public void removeListener(PropertyChangeListener listener) {
changeSupport.removePropertyChangeListener(listener);
}
public int getId() {
return id;
}
public EntryGate getEntryGate() {
return entryGate;
}
public void setEntryGate(EntryGate entryGate) {
EntryGate oldGate = this.entryGate;
this.entryGate = entryGate;
changeSupport.firePropertyChange("entryGate", oldGate, this.entryGate);
}
public ExitGate getExitGate() {
return exitGate;
}
public void setExitGate(ExitGate exitGate) {
ExitGate oldGate = this.exitGate;
this.exitGate = exitGate;
changeSupport.firePropertyChange("exitGate", oldGate, this.exitGate);
}
}
Here is an example of a JavaFX property binding.
this.idLabel.textProperty().bind(this.ticket.idProperty().asString());
Obviously I can't replace my JPA properties with SimpleXXXProperty... because they are entities participating in object relational mapping.
I am pretty new in Spring Data and I have to write what in the official documentation seems to be called Query creation from method names, here the reference:https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
As you can see in the previous example show the creation of a query by the definition of a method name, for example:
List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);
that I think return a list of Person object that have a specific email affress and a specific lastname.
So I am trying to do the same thing in my project that use Hibernate as JPA provider.
In my project I have this Twb1012Regione entity class that map the anagrafiche.TWB1012_REGIONE on the database:
#Entity
#Table(name="anagrafiche.TWB1012_REGIONE")
#NamedQuery(name="Twb1012Regione.findAll", query="SELECT t FROM Twb1012Regione t")
public class Twb1012Regione implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="COD_REG")
private String codReg;
#Column(name="COD_ARE_GEO")
private String codAreGeo;
#Column(name="COD_CIT")
private String codCit;
#Column(name="COD_IST")
private int codIst;
#Column(name="COD_PGM_ULT_MOV")
private String codPgmUltMov;
#Column(name="COD_UTE_ULT_MOV")
private String codUteUltMov;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="DAT_ORA_ULT_MOV")
private Date datOraUltMov;
#Column(name="DES_REG")
private String desReg;
//bi-directional many-to-one association to Tpg1029Provnuoist
#OneToMany(mappedBy="twb1012Regione")
private List<Tpg1029Provnuoist> tpg1029Provnuoists;
//bi-directional many-to-one association to Twb1013Provincia
#OneToMany(mappedBy="twb1012Regione")
private List<Twb1013Provincia> twb1013Provincias;
public Twb1012Regione() {
}
public String getCodReg() {
return this.codReg;
}
public void setCodReg(String codReg) {
this.codReg = codReg;
}
public String getCodAreGeo() {
return this.codAreGeo;
}
public void setCodAreGeo(String codAreGeo) {
this.codAreGeo = codAreGeo;
}
public String getCodCit() {
return this.codCit;
}
public void setCodCit(String codCit) {
this.codCit = codCit;
}
public int getCodIst() {
return this.codIst;
}
public void setCodIst(int codIst) {
this.codIst = codIst;
}
public String getCodPgmUltMov() {
return this.codPgmUltMov;
}
public void setCodPgmUltMov(String codPgmUltMov) {
this.codPgmUltMov = codPgmUltMov;
}
public String getCodUteUltMov() {
return this.codUteUltMov;
}
public void setCodUteUltMov(String codUteUltMov) {
this.codUteUltMov = codUteUltMov;
}
public Date getDatOraUltMov() {
return this.datOraUltMov;
}
public void setDatOraUltMov(Date datOraUltMov) {
this.datOraUltMov = datOraUltMov;
}
public String getDesReg() {
return this.desReg;
}
public void setDesReg(String desReg) {
this.desReg = desReg;
}
public List<Tpg1029Provnuoist> getTpg1029Provnuoists() {
return this.tpg1029Provnuoists;
}
public void setTpg1029Provnuoists(List<Tpg1029Provnuoist> tpg1029Provnuoists) {
this.tpg1029Provnuoists = tpg1029Provnuoists;
}
public Tpg1029Provnuoist addTpg1029Provnuoist(Tpg1029Provnuoist tpg1029Provnuoist) {
getTpg1029Provnuoists().add(tpg1029Provnuoist);
tpg1029Provnuoist.setTwb1012Regione(this);
return tpg1029Provnuoist;
}
public Tpg1029Provnuoist removeTpg1029Provnuoist(Tpg1029Provnuoist tpg1029Provnuoist) {
getTpg1029Provnuoists().remove(tpg1029Provnuoist);
tpg1029Provnuoist.setTwb1012Regione(null);
return tpg1029Provnuoist;
}
public List<Twb1013Provincia> getTwb1013Provincias() {
return this.twb1013Provincias;
}
public void setTwb1013Provincias(List<Twb1013Provincia> twb1013Provincias) {
this.twb1013Provincias = twb1013Provincias;
}
public Twb1013Provincia addTwb1013Provincia(Twb1013Provincia twb1013Provincia) {
getTwb1013Provincias().add(twb1013Provincia);
twb1013Provincia.setTwb1012Regione(this);
return twb1013Provincia;
}
public Twb1013Provincia removeTwb1013Provincia(Twb1013Provincia twb1013Provincia) {
getTwb1013Provincias().remove(twb1013Provincia);
twb1013Provincia.setTwb1012Regione(null);
return twb1013Provincia;
}
}
So, into my project I have defined a Twb1012RegioneRepository interface that is my repository class defined on the previous Twb1012Regione entity class:
#RepositoryDefinition(domainClass=Twb1012Regione.class, idClass=String.class)
public interface Twb1012RegioneRepository extends JpaRepository<Twb1012Regione, String> {
// I have to implement it
}
Now my problem is that I want to create 2 methods (that implement 2 queries by method name as described by the previous tutorial) that perform the following tasks:
1) Return the list of all the Twb1012Regione representing all the record of the TWB1012_REGIONE table on the DB.
2) Given a specific id (the value of the String codReg field, PK of the Twb1012Regione class) I want to obtain the Twb1012Regione object associated to this record.
How can I implement these queries? I have some difficulties to do it
Tnx
You don't need to implement the methods. The Spring Data Repository API will construct query for you as the JpaRepository already has following methods:
List findAll(Iterable ids)
T getOne(ID id)
That's the whole point with the Spring Data Repository - To reduce the boiler plate code that you write.
I have two classes setup like the following. I am confused as to when I need to annotate something as an foreign collection and when I do not. This may also sound silly, but nowhere in the ORMLite documentation does it say whether or not a non-foreign collection is allowed. What if I have a List of ints which get autoboxed into Integers? can I just persist this using a standard #DatabaseField above the Collection? A foreign collection, according to ORMLite, must also have back reference for it to work (a reference to the parent, given a one to many realtionship). For the example below, I am assuming you should annotate myBList as a foreign collection as well as making myA a foreign object, but how could you handle myStringList?
I Have seen sample code here but it doesn't answer my questions: http://ormlite.com/docs/examples
public class A {
private Set<B> myBList = new HashSet<B>();
private List<String> myStringList = new ArrayList<String>();
private long id;
public A(){}
public Set<B> getMyBList() {
return myBList;
}
public void setMyBList(Set<B> myBList) {
this.myBList = myBList;
}
public List<String> getMyStringList() {
return myStringList;
}
public void setMyStringList(List<String> myStringList) {
this.myStringList = myStringList;
}
public void setId(long id){
this.id = id;
}
public long getId(){
return id;
}
}
public class B {
private int myInt;
private String myString;
private A myA;
private long id;
public B(){}
public A getMyA(){
return myA;
}
public A setMyA(A a){
myA = a;
}
public int getMyInt() {
return myInt;
}
public void setMyInt(int myInt) {
this.myInt = myInt;
}
public String getMyString() {
return myString;
}
public void setMyString(String myString) {
this.myString = myString;
}
public void setId(long id){
this.id = id;
}
public long getId(){
return id;
}
}
#Robert is correct. When hibernate persists a collection (or even an array), it does so with hidden extra tables with foreign ids -- in other words hidden foreign collections. ORMLite tries to adhere to the KISS principle and so has you define the foreign collections "by hand" instead.
I've added more details about storing collections.
http://ormlite.com/docs/foreign-collection
This means that you cannot persist an Integer type because there is no foreign-id. Also, your code can define a foreign collection Collection<Order> or ForeignCollection<Order>. Either one will be set with a ForeignCollection. ORMLite does not support lists or other collection types.
If you want to save a Collection (such as an ArrayList) of objects to ORMLite the easiest way is this:
#DatabaseField(dataType = DataType.SERIALIZABLE)
private SerializedList<MyObject> myObjects;
and to get my list of objects:
public List<MyObject> getMyObjects() {
return myObjects;
}