Spring & neo4j: Previous relationships are deleted when adding new ones - java

Here is my User class:
#NodeEntity
public class User {
#GraphId
private Long id;
#Property
private String name;
#Property
private String email;
#Property
private String password;
#Property
private String photoLink;
#Property
private Integer age;
#Property
private Country country;
#Property
private Gender gender;
#Property
private String about;
#Property
private boolean online;
private Collection<UserHasLanguage> hasLanguage;
#Relationship(type="HAS_ROLE", direction=Relationship.OUTGOING)
private Collection<Role> roles;
#Relationship(type="HAS_IN_FRIENDLIST", direction=Relationship.OUTGOING)
private Collection<User> friendList;
#Relationship(type="HAS_IN_BLACKLIST", direction=Relationship.OUTGOING)
private Collection<User> blackList;
So I want users to have one-side relationships HAS_IN_FRIENDLIST to other users.
At the service level I have a method for adding friends to user:
public void addToFriendList (User whoAdds, User whoIsAdded)
throws UserNotFoundException{
if (whoIsAdded == null)
throw new UserNotFoundException("User not found");
Collection<User> friendList = whoAdds.getFriendList();
if (friendList == null)
friendList = new HashSet<>();
friendList.add(whoIsAdded);
whoAdds.setFriendList(friendList);
userRepository.save(whoAdds);
}
However, when I use this method, some previous relationships "HAS_IN_FRIENDLIST" of this user are removed.
I have noticed, that whoAdds.getFriendList() method always returns only 1 User.
How can I fix this?

I can't test this, but my understanding is that Collection isn't supported. For a list, you must use one of these (as specified here)
java.util.Vector
java.util.List, backed by a java.util.ArrayList
java.util.SortedSet, backed by a java.util.TreeSet
java.util.Set, backed by a java.util.HashSet
Arrays
So change Collection<User> to Set<User>

Related

How to map different country/state codes to a base entity via JPA annotations?

I have an entity with the following fields:
private Date dateOfBirth;
private String cityOfBirth;
private Long birthStateCodeId;
private Long birthCountryCodeId;
private Boolean isUSCitizen;
private Long citizenshipCountryCodeId;
private String address1;
private String address2;
private String addressCity;
private Long addressStateCodeId;
private Long addressCountryCodeId;
private String postalCode;
As you can see from the above snippet, I have
2 properties (birthStateCodeId, addressStateCodeId) where I use a state code from a StateCodes table, and
3 properties (birthCountryCodeId, citizenshipCountryCodeId, and addressCountryCodeId) where I use a country code from a CountryCodes table.
Using JPA (with Hibernate as persistence provider), how do I map the above 5 properties (2 state codes and 3 country codes) to the two separate tables StateCodes and CountryCodes?
You could achieve it like this:
#Entity
public class PersonIdentification {
// primary key
#Id // and other annotations, see JPA Spec or tutorials
private long id;
// regular attributes
private Date dateOfBirth;
private String cityOfBirth;
private Boolean isUSCitizen;
private String address1;
private String address2;
private String addressCity;
private String postalCode;
#ManyToOne
private StateCode birthStateCode;
#ManyToOne
private StateCode addressStateCode;
#ManyToOne
private CountryCode birthCountryCode;
#ManyToOne
private CountryCode addressCountryCode;
#ManyToOne
private CountryCode citizenshipCountryCode;
// setter & getter methods as needed...
}
Next, define entity classes for both "Code" types as such:
#Entity
public class StateCode {
// primary key
#Id // and other annotations, see JPA Spec or tutorials
private long id;
private String code;
private String stateName;
// other attributes of interest
// setter & getter methods as needed...
}
#Entity
public class CountryCode {
// primary key
#Id // and other annotations, see JPA Spec or tutorials
private long id;
private String code;
private String countryName;
// other attributes of interest
// setter & getter methods as needed...
}
To reduce CnP code (as with the generic aspect of primary key handling (#Id) you can check this answer. It gives you detailed hints on how handle such cases more efficiently by introducing an AbstractEntity via the #MappedSuperClass annotation.
Hope it helps

LdapRepository update spring-ldap

Spring LdapRepository save() method throws exception when I'm trying to update an existing object in LDAP database.
org.apache.directory.api.ldap.model.exception.LdapEntryAlreadyExistsException: ERR_250_ENTRY_ALREADY_EXISTS
What method should I use to update existing ldap objects?
Person class:
#Entry(objectClasses = { "inetOrgPerson", "organizationalPerson", "person", "top" })
public class Person implements Serializable {
public Person() {
}
#Id
private Name dn;
#Attribute(name = "cn")
#DnAttribute(value = "cn")
#JsonProperty("cn")
private String fullName;
#Attribute(name = "uid")
private String uid;
private String mail;
#Attribute(name = "sn")
private String surname;
//setters and getters
}
Person repo interface:
public interface PersonRepo extends LdapRepository<Person> {
}
That's how I'm updating person:
personRepo.save(person);
Default implementation for Spring LDAP repositories is SimpleLdapRepository, that checks the property annotated with #Id to determine if the objects is new - and perform create, or old - and perform update.
I'm guessing that Person.dn is null when you're trying to perform update.
You also can take the control over this by implementing org.springframework.data.domain.Persistable and place your logic in the isNew() method.
See the implementation details.

MySQL query / Hibernate Mapping not giving expected results

In my database, each user has a department and a userlevel. These are denoted in the users table with their department_id and their userlevel_id. The corresponding User java classes also has a department and userlevel field.
I need to select all the users from my db with a given username and password, and automatically map their department and userlevel object to their User object.
I have my Users, Departments and Userlevels class (automatically generated by hibernate pojo mapping) as follows:
public class Users implements java.io.Serializable {
private Integer id;
private Departments departments;
private Userlevels userlevels;
private String username;
private String password;
private String salt;
private String email;
private String firstName;
private String lastName;
public Users() {
}
//Getters and setters
}
public class Departments implements java.io.Serializable {
private Integer id;
private String name;
public Departments() {
}
//Getters and Setters
}
}
public class Userlevels implements java.io.Serializable {
private Integer id;
private String name;
public Userlevels() {
}
//Getters and Setters
}
}
I have an SQL query as such:
SQLQuery q = session.createSQLQuery("SELECT u.*,d.*,ul.* FROM users u, departments d, userlevels ul WHERE u.department_id=d.id AND u.userlevel_id=ul.id AND u.username=? AND u.password=?");
q.setString(0, "usernameToGet");
q.setString(1, "passwordToGet");
q.addEntity("u", Users.class);
q.addJoin("dept", "u.departments");
q.addJoin("ulevels", u.userlevels");
List<Users> users = q.list();
Right now I'm getting the correct User object with its corresponding department object, but the userlevels object is returning null....
Any help would be appreciated, Thanks!!

TopLink EntityManager doesn't save object properly

Really appreciate ANY help (at least ways how to trace root cause of the problem) because I've been fighting with this for several days and didn't find even workaround.
The problem itself: I have a few entities, all of them work good - persist(), find() etc. except one method where I create two different entities (Order and Items, one order can have many Items). After calling em.persist(..) order is saved and I see its id generated by DB, item is saved to DB (I see it through SELECT directly in DB) but it shows ID=0. And whatever I do it always 0 (e.g. when I open the order I still see its ID=0) until I restart server - then it shows correct ID of item.
Code of the method (after logging I added actual values I get):
public void createOrderFromItems(ArrayList<TehnomirItemDTO> items, User user) {
Order ord = new Order();
User managers = getUserByEmail(Constants.ALL_MANAGERS_GROUP);
ord.setAssignedTo(managers);
Date date = new Date();
ord.setCreatedOn(date);
User customer = user;
ord.setCustomer(customer);
BigDecimal custBalance = new BigDecimal(0);
ArrayList<Balance> balances = getBalanceForUser(customer);
for (Balance b:balances) {
custBalance.add(b.getAmount());
}
logger.debug("before1. order: "+ord.getOrderId()); //here I get 0
em.persist(ord);
logger.debug("before2. order: "+ord.getOrderId()); //still 0
State new_state = getStateByName(SharedConstants.STATE_NEW);
logger.debug("before3. order: "+ord.getOrderId()); //here I get actual ID, generated by DB, e.g. 189
State overpriced = getStateByName(SharedConstants.STATE_LIMIT_EXCEEDED);
ArrayList<Item> itemList = new ArrayList<Item>();
for (TehnomirItemDTO tid:items) {
Item item = new Item(tid);
item.setOrder(ord);
logger.debug("order inside2:"+ord.getOrderId()); //again, actual ID
item.setPriceInt(tid.getPrice_int());
custBalance = custBalance.subtract(item.getPriceInt());
if (custBalance.floatValue()>0) {
item.setStateBean(new_state);
} else item.setStateBean(overpriced);
logger.debug("item before:"+item.getItemId()); //here I get 0
em.persist(item);
item = em.merge(item);
em.setFlushMode(FlushModeType.COMMIT);//added just in case it would work but it didn't
em.flush();//same as previous line
Item tst = getItemByID(1);
logger.debug("item after:"+item.getItemId()+" ord:"+ord.getOrderId()); //again, orderID is correct, itemID is 0
itemList.add(item);
}
ord.setItems(itemList);
State new_state2 = getStateByName(SharedConstants.STATE_NEW);
logger.debug(ord.getItems().get(0).getItemId()+" order: "+ord.getOrderId());//again, orderID is correct, itemID is 0
}
Order class:
#Entity
#Table(name="orders")
public class Order implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY/*, generator="ORDERS_ORDERID_GENERATOR"*/)
#Column(name="ORDER_ID")
private int orderId;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="CREATED_ON")
private Date createdOn;
//bi-directional many-to-one association to Item
#OneToMany(mappedBy="order")
private List<Item> items;
//uni-directional many-to-one association to User
#ManyToOne
#JoinColumn(name="ASSIGNED_TO")
private User assignedTo;
//uni-directional many-to-one association to User
#ManyToOne
#JoinColumn(name="CUSTOMER")
private User customer;
public Order() {
}
public int getOrderId() {
return this.orderId;
}
}
Item class (removed getters and setters to make it more readable):
#Entity
#Table(name="items")
public class Item implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="ITEM_ID")
private int itemId;
private String code;
private BigDecimal weight;
public BigDecimal getWeight() {
return weight;
}
public void setWeight(BigDecimal weight) {
this.weight = weight;
}
private String comments;//any additional info user'd like to add
private String description;
#Column(name="EXT_ID")
private int extId;
private String manufacturer;
#Column(name="PRICE_EXT")
private BigDecimal priceExt;
#Column(name="PRICE_INT")
private BigDecimal priceInt;
private String region;
private String term;
//bi-directional many-to-one association to Order
#ManyToOne(cascade=CascadeType.PERSIST)
#JoinColumn(name="ORDER_ID")
private Order order;
//bi-directional many-to-one association to State
#ManyToOne
#JoinColumn(name="STATE")
private State state;
}
I had some thoughts about caching so I added to my persistence.xml lines
property name="toplink.cache.type.default" value="NONE"
property name="toplink.cache.type.Order" value="NONE"
but it didn't help either
Try to change int to Integer
private Integer orderId;
and getters and setters as well.
You mention Item is assigned an ID value by the database, but missed the #GeneratedValue(strategy=GenerationType.IDENTITY) annotation you have on order. This is what tells JPA the db controls the value, otherwise it expects the application to set it, keeping it the default 0.
after calling em.persist(obj), call em.flush();. It should work.
better have a private method save
like
private void save(object obj)
{
em.persist(obj);
em.flush();
}

Relationships in Google App Engine

I have just one week experience in GAE/Java and trying to port an legacy application(developed using PHP/MySQL) to GAE+JDO. I'm now stuck with a basic issue in creating a relationship between two tables(kinds in GAE).
So here is the case:
We have a Users table which holds the user authentication information. It also has a field user_role which store role_id, which is actually a foreign key of another table user_roles.
From the the Entity-Relationship documentation in GAE, I understand that DataStore doesn't support foreign-key relationships and designed the Users class by adapting the Employee-ContactInfo example in the docs.
When I executed the application, the user_roles kind is inserted each time I add an entry in Users table. The user_roles kind is supposed to have only three static values. But this is having redundant values as I input more records in Users.
I think that I'm missing something very trivial, but I couldn't figure it out due to my inexperience to datastore. It would be very nice if someone could guide me to solve this issue.
Here is the code:
#PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Users {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent
private String userName;
#Persistent
private String password;
#Persistent
private String salt;
#Persistent
private Date createdDate;
#Persistent
private Key createdBy;
#Persistent
private Date lastLogin;
#Persistent
private boolean status;
#Persistent
private String authKey;
#Persistent(defaultFetchGroup="true")
private SecurityRole securityRole;
#Autowired
SecurityRepository securityRepository ;
public SecurityPrincipals(String userName, String password,SecurityRole securityRole,boolean status) {
this.securityRole = securityRole;
this.userName = userName;
this.password = password;
this.status = status;
}
//getters and setters
}
Definition for Roles:
#PersistenceCapable(detachable="true")
public class SecurityRole {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent
private String securityRoleName;
#Persistent
private String securityRoleDescription;
#Persistent
private String securityRoleStatus;
#Persistent
private Date securityRoleCreatedDate;
public SecurityRole(String securityRoleName, String securityRoleDescription, String securityRoleStatus,String securityBaseType)
{
this.securityRoleName = securityRoleName;
this.securityRoleDescription = securityRoleDescription;
this.securityRoleStatus = securityRoleStatus;
this.securityBaseType = securityBaseType;
}
// getters and setters
}
The relevant code from Controller:
SecurityRole securityRole = securityRepository.getSecurityRole( securityRoleName);
users = new Users(userName,password,status,securityRole);
iUserRepository.save(employeeDetails);
Here is the definition of getSecurityRole:
public SecurityRole getSecurityRole(String securityRoleName)
{
PersistenceManagerFactory pmf = this.jdoTemplate.getPersistenceManagerFactory();
PersistenceManager pm = pmf.getPersistenceManager();
try {
Query query = pm.newQuery( SecurityRole.class);
query.declareImports("import java.lang.String");
query.declareParameters("String securityRoleName");
query.setFilter("this.securityRoleName == securityRoleName");
List<SecurityRole> securityRoles = (List<SecurityRole>)query.execute(new String(securityRoleName));
SecurityRole temp = null;
for(SecurityRole securityRole: securityRoles)
{
temp = securityRole;
}
return temp;
}
finally {
pm.close();
}
}
Here is the definition of iUserRepository.save():
public void save(Users user) {
jdoTemplate.makePersistent(companyDetails);
}
In the Users class, you have the defined the property
#Persistent(defaultFetchGroup="true")
private SecurityRole securityRole;
This statement creates an "owned" relationship in GAE datastore, which means that when you create an object of the Users class, an object of the SecurityRole class will be created as well.
What you need, is an unowned relationship that can be created as follows:
#Persistent(defaultFetchGroup="true")
private Key securityRole;
In this way, a SecurityRole object is not created each time you create an instance of the Users class. For more information about owned and unowned relationships, take a look at http://code.google.com/appengine/docs/java/datastore/jdo/relationships.html
Hope this helps!

Categories