really strange situation I got here. I have 2 classes.
#Entity
public class CategoryData extends EntityData {
public Long parentId;
#Column(unique=true)
public String name;
public Picture picture;
}
#Entity
public class PropertyGroupData extends EntityData {
public Long categoryId;
public String adminDescription;
public String title;
#ManyToMany(fetch=FetchType.EAGER)
public List properties = new LinkedList();
}
this is the entity class for my hibernate.
#MappedSuperclass
public class EntityData implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long id;
#Temporal(TemporalType.TIMESTAMP)
public Date created = new Date();
#Temporal(TemporalType.TIMESTAMP)
public Date modified = new Date();
public Long version = 0L;
// W:waiting,A:active,D:deleted
public Character status;
#Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
#Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.DEFAULT_STYLE);
//return "EntityData[id=" + id + "]";
}
}
here comes the situation. I got some data in my database and it works well. until now.
for(CategoryData c:kategoriler)
if(pgd.categoryId.toString().equals(c.id.toString()))
out.print("1-find equal "+c.id);
for(CategoryData c:kategoriler)
if(pgd.categoryId==c.id)
out.print("2-find equal "+c.id);
the first for loop works normally and prints 1-find equal 7 but second loop does not print anything. they both Long. what am I doing wrong ?
The expressions are of type Long, which is a class, and are therefore compared by reference identity. If they were long, it would be fine. Try this instead:
for(CategoryData c:kategoriler)
if(pgd.categoryId.longValue() == c.id.longValue())
out.print("2-find equal "+c.id);
You're comparing 2 objects by reference. That is, you're checking whether they're references to the same object. What you want is to check if they have the same values, e.g.
if(pgd.categoryId.longValue() == c.id.longValue())
Since Long overrides the .equals, you can use the .equals() method, just like you do with strings.
for(CategoryData c:kategoriler)
{
if (pgd.categoryId.equals(c.id))
{
out.print("2-find equal "+c.id);
}
}
Using the == just compares the object references.
Related
I'm starting to step into the Java world and I'm having troubles to understand this.
I'm using JPA to interact with my database with JPQL.
I have a persistent class like this one :
#Entity
#Table(name="C_A_T")
#NamedQuery(name="CAT.findAll", query="SELECT c FROM CAT c")
public class CAT implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private CATPK id;
private String offer;
#Temporal(TemporalType.DATE)
#Column(name="MODIF_DATE")
private Date modifDate;
public CAT() {}
public CATPK getId() {return id;}
public void setId(CATPK id) {this.id = id;}
public String getOffer() {return offer;}
public void setOffer(String offer) {this.offer = offer;}
public Date getModifDate() {return modifDate;}
public void setModifDate(Date modifDate) {this.modifDate= modifDate;}
/* ... */
}
The class CATPK represents a primary key of an instance of CAT :
#Embeddable
public class CATPKimplements Serializable {
//default serial version id, required for serializable classes.
private static final long serialVersionUID = 1L;
#Column(name="ID_CAT")
private String idCAT;
#Column(name="ID_DEMANDE")
private String idDemande;
public CATPK() {}
public String getIdCAT() {return this.idCAT;}
public void setIdCAT(String idCAT) {this.idCat= idCat;}
public String getIdDemande() {return this.idDemande;}
public void setIdDemande(String idDemande) {this.idDemande = idDemande;}
/* ...*/
}
So basicly, the primay key is made of 2 different ID.
Now, sometimes, before inserting a CAT in my database I checked if it is not already in the C_A_T table :
EntityManagerFactory emf = Persistence.createEntityManagerFactory("cie");
em = emf.createEntityManager();
em.getTransaction().begin();
// inCAT is an instance of CAT on which there is a complete primary key CATPK (made of 2 id)
CAT CATinDB = em.find( CAT.class, inCAT.getId() );
if (null == CATinDB)
em.persist(inCAT); // CAT created
em.getTransaction().commit();
em.close();
Now, the problem is that the line em.find( CAT.class, inCAT.getId() ); doesn't return null when it should.
For instance, CATinDB can contain a row when I actually have no rows with the right idCAT and idDemande.
So will find consider that it is found with only one id of the catPK matching ?
In the end, I changed the line :
if (null == CATinDB)
into :
if (null == CATinDB || CATinDB.getId().getIdCAT() != inCAT.getId().getIdCAT() || CATinDB.getId().getIdDemande() != inCAT.getId().getIdDemande())
Not really sure why find wasn't returning null when I had no records matching the 2 id.
Actually, I just needed to restart my weblogic server. Looks like the data source is not dynamically updated when I update the database.
I am working on a project where code gets automatically generated based upon an MySQL library. It is somewhat like JPA, but not quite.
This is an example bean:
public class TemplateBean implements Bean {
private Integer templateId;
private Integer businessPartnerId;
public TemplateBean(final Integer businessPartnerId) {
this.businessPartnerId = businessPartnerId;
}
private TemplateBean(final Object nullObject, final Integer templateId, final Integer businessPartnerId) {
this.templateId = templateId;
this.businessPartnerId = businessPartnerId;
}
public TemplateBean(final ResultSet rs) throws SQLException {
this(null, rs.getInt(1), rs.getInt(2));
}
public Integer getTemplateId() {
return templateId;
}
public void setTemplateId(final Integer templateId) {
this.templateId = templateId;
}
public Integer getBusinessPartnerId() {
return businessPartnerId;
}
public void setBusinessPartnerId(final Integer businessPartnerId) {
this.businessPartnerId = businessPartnerId;
}
#Override
public String toString() {
return "Template(" + templateId + ", " + businessPartnerId + ")";
}
}
Now I need it to implement equals() and hashCode(). I of course have access to all data that is available from SQL, so I think implementing equals() should be doable, but how am I going to create a good hashCode()?
Any tips will be appreciated.
I would like to suggest to use EqualsBuilder
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
public class Person {
private String id;
private String name;
private String address;
private String phone;
private String version;
#Override
public boolean equals(Object object) {
return EqualsBuilder.reflectionEquals(this, object,);
}
#Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
or
/*
* equal() method with exclude fields.
* it will neglect id and version fields.
*
* */
#Override
public boolean equals(Object object) {
return EqualsBuilder.reflectionEquals(this, object, "id", "version");
}
}
One very convenient way is to use the #EqualsAndHashCode annotation provided by Groovy. Using this is as simple as
#EqualsAndHashCode
public class TemplateBean implements Bean {
// implementation omitted
}
This will generate equals() and hashCode() methods based on the class' properties using an algorithm similar to the one outlined in the book Effective Java.
Because the annotation is implemented via an AST transformation, it can be used in Java or Groovy classes, though you will of course need the Groovy library on your classpath to use it.
Working with JPA, I would like to be able to save a BitSet to the DB and pull it back of course.
Suppose I have:
#Entity
#Table(name = "myTable")
public class MyClass {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "Object_Id")
protected long id;
#Column(name = "Tags")
protected BitSet tags;
... getters & setters etc...
}
Should I define a "columnDefinition" as well? I don't really understand how it is persisted (using toString()?) and moreover how does it get loaded back from the DB.
Can you please help me with this one?
Thanks!
More efficient way (that uses int instead of byte[]) requires a pretty simple custom class:
#Entity
#Access(AccessType.FIELD)
public class SampleEntity {
#Transient
private IntBitSet isolationLevel = new IntBitSet(0);
public static final int USER_BIT = 0;
public static final int DEVICE_BIT = 1;
// 2, 3, 4, ...
public boolean isUserIsolated() {
return isolationLevel.bitGet(USER_BIT);
}
public boolean isDeviceIsolated() {
return isolationLevel.bitGet(DEVICE_BIT);
}
public void setUserIsolated(boolean b) {
isolationLevel.bitSet(USER_BIT, b);
}
public void setDeviceIsolated(boolean b) {
isolationLevel.bitSet(DEVICE_BIT, b);
}
#Access(AccessType.PROPERTY)
#Column
public int getIsolationLevel() {
return isolationLevel.getValue();
}
public void setIsolationLevel(int isolationLevel) {
this.isolationLevel = new IntBitSet(isolationLevel);
}
private static class IntBitSet {
private int value;
public IntBitSet(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public boolean bitGet(int i) {
return ((value >> i) & 1) == 1;
}
public void bitSet(int i, boolean b) {
if (b) {
bitSet(i);
} else {
bitUnset(i);
}
}
private void bitSet(int i) {
value = value | (1 << i);
}
private void bitUnset(int i) {
value = value & ~(1 << i);
}
}
}
By default JPA uses Java serialization to persist properties of unknown Serializable types (so that you have a serialized representation stored as a byte[]).
Usually it's not what you want, because there can be more efficient ways to represent your data. For example, BitSet can be efficiently represented as a number (if its size is limited), or byte[], or something else (unfortunately, BitSet doesn't provide methods to do these conversions, therefore you need to implement them manually).
When you've decided what kind of data representation you want to have in the database you need to tell JPA to apply the necessary conversion. There are two options:
Implement conversion in getters and setters. For example, as follows:
#Entity
#Table(name = "myTable")
#Access(AccessType.FIELD)
public class MyClass {
...
#Transient // Do not store this field
protected BitSet tags;
#Access(AccessType.PROPERTY) // Store the property instead
#Column(name = "Tags")
byte[] getTagsInDbRepresentation() {
... // Do conversion
}
void setTagsInDbRepresentation(byte[] data) {
... // Do conversion
}
...
}
Use provider-specific extension to perform the conversion implicitly (for example, custom types in Hibernate). This approach allows you to reuse your type conversion logic in different entities.
You can use any of the following conversion in the getter method
byte[] bytes = bitSet.toByteArray();
long[] longs = bitSet.toLongArray();
I'm working on a jpa project where I persist multiple instances of a Band object which contains an ArrayList of Date objects.
I want to query the database to obtain Bands, which ArrayLists contain the specified Date.
Is this possible? I am aware my entire design could be bad but I'm hoping this is possible, as I am aware that you need a get method to use object parameters, so the method must be called somewhere.
I want to use something along these lines:
Date d = new Date();
List bands = em.createQuery("select b from Band b where b.dates.contains(d)").getResultList();
//I am aware I may need to set up d as an argument.
This is the Band entity as requested. Assume package and imports are correct.
#Entity
#Table(name = "BAND")
public class Band extends SuperUser {
#Column(name = "PHONENUMBER")
private String phoneNumber;
#Column(name = "BIOGRAPHY")
private String biography;
#Column(name = "DATES")
private ArrayList<Date> dates = new<Date> ArrayList();
public Band() {
}
public Band(String n, String e, String p, String ph_no, String bio) {
super(n, e, p);
this.phoneNumber = ph_no;
this.biography = bio;
}
public void setPhoneNumber(String p) {
this.phoneNumber = p;
}
public String getPhoneNumber() {
return this.phoneNumber;
}
public void setBoigraphy(String b) {
this.biography = b;
}
public String getBiography() {
return this.biography;
}
public void setDate(Date d) {
dates.add(d);
}
public void cancelDate(Date d) {
while (dates.remove(d)) {
}
}
public ArrayList getDates() {
return dates;
}
}
EDIT: I got it working. I Didn't know about elementcollections and temporal types, changing the date list to:
#ElementCollection
#Temporal(TemporalType.DATE)
private List<Date> dates = new <Date>ArrayList();
fixed it.
I think what you're looking for is "Member Of": http://www.objectdb.com/java/jpa/query/jpql/collection#NOT_MEMBER_OF_
select b from Band b where :d member of b.dates
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;
}