I am implementing a banking application and have three tables in my database (User, Account and AccountActivity):
The implementation of the Account and AccountActivity classes look like this:
#MappedSuperclass public abstract class AbstractDomain implements Serializable {
#Id #GeneratedValue
private long id = NEW_ID;
public static long NEW_ID = -1;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public boolean isNew() {
return id==NEW_ID;
}
}
#Table(name="ACCOUNT_ACTIVITY")
#Entity
public class AccountActivity extends AbstractDomain {
#Column(name="NAME")
private String Name;
#Column(name="XDATE")
private Date Date;
#Column(name="VALUE")
private double Value;
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name="ACCOUNTID")
private Account ACCOUNT;
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name="OTHERACCOUNTID")
private Account OTHERACCOUNT;
public String getName() {
return Name;
}
// ...
}
And:
#Table(name="ACCOUNT")
#Entity
public class Account extends AbstractDomain {
#Column(name="NAME")
private String Name;
#Column(name="XDATE")
private Date Date;
#Column(name="VALUE")
private double Value;
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name="USERID")
private User USER;
#OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
private List<AccountActivity> AccountActivity = new ArrayList<AccountActivity>();
// ...
}
To store new accounts in my database I use this:
public Account storeAccount(Account ac) {
User x = ac.getUser();
x = em.merge(x);
ac = em.merge(ac);
return ac;
}
which works to just store new accounts in my database. I wanted to implement the functionality that when account activity information is added to an already saved account,
that account will be updated and the added information (account activity) is cascaded to the
AccountActivity table using this piece of code:
#OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
private List<AccountActivity> AccountActivity = new ArrayList<AccountActivity>();
When I test this code I get the error:
java.sql.SQLException: Integrity constraint violation -no parent
FK670B7D019607336A table: ACCOUNT_ACTIVITY in statement
Can anybody help me with this problem?
update
I test with this piece of junit code:
public void testAddAccountActivities() {
User user = dummyPersistedUser();
User user2 = dummyPersistedUser();
Account account = getTestUtils().dummyEmptyAccount(user);
Account account2 = getTestUtils().dummyEmptyAccount(user2);
account=accountManager.storeAccount(account);
account2=accountManager.storeAccount(account2);
getTestUtils().fillAccounts(account, account2);
accountManager.storeAccount(account);
accountManager.storeAccount(account2);
assertEquals(2,accountManager.getAccount4Name(account.getName()).getAccountActivity().size());
assertEquals(2,accountManager.getAccount4Name(account2.getName()).getAccountActivity().size());
}
where fillAccounts(account, account2) just inserts some AccountActivities that should be added to the graph.:
AccountActivity aa = new AccountActivity();
aa.setDate(new Date());
aa.setName("test activity");
aa.setAccount(a1);
aa.setValue(value);
aa.setOtherAccount(a2);
account.addAccountActivity(aa)
#OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
#JoinColumn(name ="accountid") // you have several references from AccountActivity to Account. You need to specify the join column in this case.
private List<AccountActivity> AccountActivity = new ArrayList<AccountActivity>();
As a first observation, I think you shouldn't have the variable name the same as the class. So, instead of this private List <AccountActivity> AccountActivity, you can write something like private List <AccountActivity> accountActivity.
Related
Hello have problems with saving relation ships with NEO4J and Spring, I can save relationships when I don't use a class with #RelationProperties, but whenever I want to use that class the relationships are not even created.
I am using Neo4j 4.3.7-community edition in a docker container
And in my pom.xml i have
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j</artifactId>
<version>6.1.5</version>
</dependency>
I want to do something like this
Image
I have this bit of code :
starting node
...
#Relationship(type = "VISITS",direction = Relationship.Direction.OUTGOING)
public Set<Visits> visits;
public void visitPOI(Visits visit) {
if(visits == null) {
visits = new HashSet<>();
}
visits.add(visit);
}
...
My relation
#RelationshipProperties
public class Visits {
#Id #GeneratedValue
private long id;
#Property private String description;
#TargetNode private PointOfInterest poi;
public Visits(String description, PointOfInterest p){
this.description = description;
this.poi = p;
}
...
and the destination node
...
#Node
public class PointOfInterest {
#Id #GeneratedValue(generatorClass = UUIDStringGenerator.class)
private String id;
#Property private String name;
#Property private double lat;
#Property private double lng;
public PointOfInterest() { }
//getters and setters
...
And this in a service
...
public void saveRelation(String username, Visits v ){
User u = userRepository.findByUserName(username);
Optional<PointOfInterest> poi = pointOfInterestRepository.findById(v.getPoi().getId());
v.setPoi(poi.get());
u.visitPOI(v);
userRepository.save(u);
}
...
and the JSON I post
{
"description":"Nice trip",
"poi":{
"id":"Uster"
}
}
Use #RelationshipId on id field of #RelationshipProperties as follow
#RelationshipProperties
public class Visits {
#RelationshipId
private long id;
#Property private String description;
.....
}
I had the same issue with persisting relationship properties using #RelationshipProperty annotated class. Finally, I discovered that the issue is due to the implicit conversion between long and Long. Changing #RelationshipId private long id; to #RelationshipId private Long id; inside the #RelationshipProperty annotated class will do the trick. This appears to be a bug in SDN, it should report an error instead.
I'm trying to build simple REST for purchases I need 2 methods. The first method should show all purchases sorted by date. The second one removes all purchases for specified date I made a method to add and to get all purchases. Now I'm stuck.
#Entity
#Table (name="purchase")
public class Purchase {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name")
private String name;
#CreationTimestamp
#Temporal(TemporalType.DATE)
#Column(name="createat")
private Date created;
#Column(name="price")
private BigDecimal price;
#Column(name="currency")
private String currency;
#Repository
public interface PurchaseRepository extends JpaRepository<Purchase, Long>
{
}
#Service
public class PurchaseService {
#Autowired
private PurchaseRepository purchaseRepository;
public void addPurchase(Purchase purchase) {
purchaseRepository.save(purchase);
}
public List<Purchase> getAllPurchase() {
List<Purchase> purchase = new ArrayList<>();
purchaseRepository.findAll().forEach(purchase::add);
return purchase;
}
}
#RestController
public class PurchaseController {
#Autowired
private PurchaseService purchaseService;
#PostMapping("/purchase")
public void addPurchase(#RequestBody Purchase purchase) {
purchaseService.addPurchase(purchase);
}
#RequestMapping("/purchase")
public List<Purchase> getAllTopics() {
return purchaseService.getAllPurchase();
}
}
What I need:
1. method to sort my List sorted by date
2. method that removes all purchases for specified date
You can use Spring Data JPA features in these cases.
Add the following methods to PurchaseRepository:
List<Purchase> findAllByOrderByCreatedAsc();
long deleteByCreated(Date created);
And after all, Spring is going to generate an appropriate query based on a method name.
I got it
long deleteByCreated(Date date);
#Transactional
public long deleteAllByDate(Date date){
return purchaseRepository.deleteByCreated(date);
}
#RequestMapping(method=RequestMethod.DELETE, value="/purchasess/{date}")
public long findAllByCreatedBetween(#DateTimeFormat(pattern="yyyy-MM-dd")
#PathVariable Date date){
return purchaseService.deleteAllByDate(date);
}
I am using a typical User -> Role relationship with my application. I am taking advantage of Neo4j's ability to add metadata on the relationship through the RelationshipEntity annotation. For some unexplained reason the Role's properties are being 'nulled' out when I persists my relationship.
Here's my User
public class Person {
#GraphId Long id;
private String name;
#RelatedToVia(type="HAS_ROLE")
#Fetch
private Set<UserRoleRelationship> roles = new HashSet<UserRoleRelationship>();
public Person() {}
public Person(String name) { this.name = name; }
}
Role
#NodeEntity
public class Role {
#GraphId Long id;
private RoleType roleType;
#SuppressWarnings("unused")
private String roleName;
private #Fetch Set<Privilege> defaultPrivileges;
}
RelationshipEntity
#RelationshipEntity(type="HAS_ROLE")
public class UserRoleRelationship {
#GraphId Long id;
#StartNode private Person person;
#EndNode private Role role;
private List<Privilege> privileges = new ArrayList<Privilege>();
}
RoleType (Used in Role)
public enum RoleType {
ADMIN("Administrator", Arrays.asList(new Privilege(PrivilegeType.PRIV1.name()),
new Privilege(PrivilegeType.PRIV2.name()),
new Privilege(PrivilegeType.PRIV3.name()),
new Privilege(PrivilegeType.PRIV4.name()))),
USER("User", Arrays.asList(new Privilege(PrivilegeType.PRIV1.name()))),
private String name;
private Set<Privilege> defaultPrivileges = new HashSet<Privilege>();
private RoleType(String name, List<Privilege> privileges){
this.name=name;
this.defaultPrivileges=new HashSet<Privilege>(privileges);
}
public String getName() {
return name;
}
public Set<Privilege> getDefaultPrivileges() {
return defaultPrivileges;
}
}
When populating the relationship with a User and Role, all the data is set. However when I persists it the Role's data is now null.
// Before Save
UserRoleRelationship [id=null, person=Person [id=26, name=TestUser, roles=1], **role=Role [id=27, roleType=ADMIN, defaultPrivileges=[PRIV4, PRIV1, PRIV2, PRIV3]]**]
// After Save
UserRoleRelationship [id=6, person=Person [id=26, name=TestUser, roles=0], **role=Role [id=27, roleType=null, defaultPrivileges=null]**]
Any ideas as to why this is occurring to my Role Object?
Also, here are my Repos
public interface PersonRepository extends CrudRepository<Person, String> {
Person findByName(String name);
}
public interface RoleRepository extends CRUDRepository<Role> {
Role findByRoleType(RoleType rt);
Role findByRoleName(String name);
}
public interface UserRoleRepository extends CrudRepository<UserRoleRelationship, String> {}
It repopulates the UserRoleRelationship after saving.
As you don't have a #Fetch annotation on neither the start nor end-node it only loads them in a shallow fashion.
I don't recommend to add #Fetch there because it can easily load your whole graph, so I'd probably use
template.fetch(rel.person);
template.fetch(rel.role);
I have this Play Model class that I'm trying to modify an object of, and when I want to save it, I get the following exception:
java.lang.RuntimeException: No #javax.persistence.Id field found in class [class models.Contact]
at play.db.ebean.Model._idAccessors(Model.java:39)
at play.db.ebean.Model._getId(Model.java:52)
The class:
#Entity
public class Contact extends Model implements Person {//, Comparable<Contact>{
private Long id;
private Client client;
#Required
private String email;
private String profil_picture;
private Boolean active = new Boolean(true);
private Boolean favorite = new Boolean(false);
#Transient
private Boolean profile_pic_url_init = new Boolean(false);
#Id
#GeneratedValue
public Long getId() {
return id;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="client_id")
public Client getClient(){
return client;
}
public void setClient(Client client){
this.client= client;
}
#Column
public Boolean getFavorite() {
return favorite;
}
public void setFavorite(Boolean is_favorite) {
this.favorite = is_favorite;
}
....
}
The code calling the save() method:
List<Contact> contacts_list = current_client.getContacts();
for (Contact c : contacts_list) {
c.setFavorite(false);
c.save();
}
The class actually has an #Id annotation, so any guesses of why this doesn't work? I tried looking it up on google, but couldn't find much about this error. Thanks in advance!
Move #Id annotation to id field instead of its getter.
I'm learning Hibernate and Play framework (also add Java into account...). I'm having problems saving this kind of entity
#Entity
#Table(name="users")
public class User extends Model {
#Required
public String username;
#Column(name="user_displayname",nullable=true)
public String displayname;
#Password
public String user_password;
#Email
#Column(name="user_email",nullable=false,unique=true)
public String user_email;
public String user_salt;
public Date user_joindate;
#ManyToOne
#JoinTable(name="users_meta")
public UserMeta userdata;
#Required
public boolean user_isActive;
#OneToOne(targetEntity=UserPhotos.class,cascade=CascadeType.ALL)
#JoinColumn(name="id",referencedColumnName="userID")
public UserPhotos userPhoto;
#ManyToMany(cascade=CascadeType.ALL)
#JoinTable(name="links_rol2user")
public List<Rol> rol;
public User (String username, models.Pass password, String user_email) {
this.username = username;
this.user_password = password.getHashedPassword();
this.user_salt = password.getUserHash();
this.user_email = user_email;
this.user_joindate = new Date();
this.user_isActive = false;
}
This is my code when I'm registering a user
// check if the validation has errors
if(validation.hasErrors()) {
params.flash(); // add http parameters to the flash scope
validation.keep(); // keep the errors for the next request
register();
} else {
Cache.delete(uuid);
Pass pass = new Pass(password,new Date().toString());
User newUser = new User(firstName, pass, email);
UserMeta utest = new UserMeta(newUser.id);
utest.setUserTownID(pueblos);
newUser.setUserMeta(utest);
newUser.save();
Logger.info("NewUser ID : %s", newUser.getId());
// UserMeta userInfo = new UserMeta(newUser.getId());
// userInfo.setUserTownID(pueblos);
// userInfo.save();
// TODO salvar foto a null
// Confirmation left
Cache.set("thankyou", "alright!", "3mn");
thankyou();
}
I'm trying to save the userMeta, it does creates a new record when I set the userMeta object into newUser (not visible right now), but it doesn't insert the new ID created in newUser.
What kind of relation do I need? before I tweaked the code as it is now, it was a OneToOne relationship, worked quite well, but now when I was completing the register functions it kinda hit me that I needed to save userMeta object too..
If you need more info let me know, I don't know if I explained it well or not, just trying to get the hang of how Hibernate do relations, etc.
Adding UserMeta:
*/
#Entity
#Table(name="users_meta")
public class UserMeta extends Model {
#Lob
#Column(name="userBio")
public String userBio;
#Column(name="userPhotoID",nullable=true)
public Long userPhotoID = null;
#Column(name="userRoleID", nullable=false)
public Long userRoleID = 2L;
#Lob
public String userDescription;
#Column(name="userViews", nullable=false)
public Long userViews = 0L;
#Column(name="userFavoriteCount", nullable=false)
public Long userFavoriteCount = 0L;
#Column(name="userTotalComments", nullable=false)
public Long userTotalComments = 0L;
#Column(name="userTotalUploadedVideos", nullable=false)
public Long userTotalUploadedVideos = 0L;
public Long userTownID;
public Long userID;
public UserMeta() {}
public UserMeta(Long userid) {
this.userBio = "El usuario no ha escrito nada todavia!";
this.userDescription = "El usuario todavia no se ha describido!";
this.userID = userid;
}
public Long getUserTownID() {
return userTownID;
}
public void setUserTownID(Long userTownID) {
this.userTownID = userTownID;
}
}
// pass model
public class Pass {
protected String hashed;
protected String userHash;
public Pass(String passwordToHash, String salt) {
StringBuffer passSalt = new StringBuffer(passwordToHash);
this.userHash = DigestUtils.md5Hex(salt);
passSalt.append(this.userHash);
passSalt.append(Play.configuration.getProperty("application.passwordSalt"));
this.hashed = DigestUtils.sha512Hex(passSalt.toString());
}
public String getHashedPassword() {
return this.hashed;
}
public String getUserHash() {
return this.userHash;
}
}
There seems to be a lot going on there! But from what I can tell, you problem is with the id that you are passing into the UserMeta.
As you are extending Model, the id is being generated by the Model class. However, this is not set until after the entity is saved to the database (as the id is auto-generated by the database).
Therefore, because you are passing the id into the UserMeta before the User object is saved, the value of id will be null.
If you can save the User object before you create your UserMeta object, your code should work.