this is my configuration
#EnableTransactionManagement
#EnableScheduling
#EnableAutoConfiguration
#ComponentScan(basePackages = {"id.co.babe.neo4j.service"})
#Configuration
public class MyNeo4jConfiguration extends Neo4jConfiguration {
private static final Logger LOGGER = LoggerFactory.getLogger(MyNeo4jConfiguration.class);
#Value("${neo4j.server.user}")
private String user;
#Value("${neo4j.server.pass}")
private String pass;
#Value("${neo4j.server.host}")
private String host;
#Override
public Neo4jServer neo4jServer() {
return new RemoteServer(host,user,pass);
}
#Override
public SessionFactory getSessionFactory() {
return new SessionFactory("app.neo4j.domain");
}
#Bean
#Primary
public Neo4jOperations getNeo4jTemplate() throws Exception {
return new Neo4jTemplate(getSession());
}
and this is my domain User
#NodeEntity
public class User{
#GraphId
private Long Id;
private String name;
private int age;
private String country;
and my service interface
public interface UserService {
public User create(User user);
public User read(User user);
public List<User> readAll();
public User update(User user);
public Boolean delete(User user);
}
and my implementation
#Service
#Transactional
public class UserServiceImpl implements UserService{
#Autowired
Neo4jOperations template;
#Override
public User create(User user){
return template.save(user);
}
and this is my main class
for(int i = 0; i < 10; i++){
app.neo4j.domain.User user = new app.neo4j.domain.User();
user.setAge(13);
user.setCountry("Philly");
user.setId(i);
user.setName("Ibanez" + i);
LOGGER.info("Inserting {}",user.getName());
service.create(user);
}
no error was found, but when I go to neo4j console (localhost:7474), and run this query match(n) return n, which should return all nodes in the database. unfortunately there was no nodes found even though i was able to save without errors. I wonder what's wrong.
I also tried doing it with #enablingNeo4jRepositories with no difference to the result.
Your code should never set the value of the #GraphId field. This field is used internally to attach entities to the graph.
If you remove user.setId(i);, your entities should be saved correctly.
Note that you can add your own custom ID field, but you still need another field for the GraphID e.g.
#GraphId private Long graphId; //used internally, never assign a value
private Long id; //your application id, stored as a property on the entity
Related
I'm newbie with Java. I'm create an API with Webflux and ReactiveMongoRepository.
I try to save my data from another API.
My repository:
#Repository
public interface AccountApiTrackingRepo extends ReactiveMongoRepository<AccountApiTracking, String> {
}
My service implements:
#Override
public void findByIdAccountsApiTrack(User user, String accountId){
AccountApiTracking accountApiTracking = new AccountApiTracking();
accountApiTracking.setUser(user);
accountApiTracking.setAccountId(accountId);
accountApiTracking.setAction("Find account by Id");
System.out.println(accountApiTracking);
accountApiTrackingRepo.save(accountApiTracking);
}
My services:
#Service
public interface AccountApiTrackingService {
public void createAccountsApiTrack(User user, AccountDto accountDto);
public void findByIdAccountsApiTrack(User user, String accountId);
Flux<AccountApiTrackingDto> findAll();
}
My model:
#Document
#Data
#NoArgsConstructor
#AllArgsConstructor
public class AccountApiTracking implements AutoMapping<AccountApiTrackingDto> {
#Id
private String id;
private User user;
private String action;
private AccountDto payload;
private String accountId;
#Override
public String toString() {
return String.valueOf(action);
}
}
After function findByIdAccountsApiTrack() run I can't find any document created in my database.
I can see my variable accountApiTracking have data. But accountApiTrackingRepo.save doesn't work.
What I'm missing?
In Reactive programming should subscribe to any reactive instruction.
you should
return accountApiTrackingRepo.save(accountApiTracking);
to till your usage for example in the controller.
or for your test case, you can use ".subscribe()" after your method call.
This question already has answers here:
Update or saveorUpdate in CRUDRepository
(2 answers)
Closed 3 years ago.
I am processing a Post request with Json data, how do I add them to the database, so that there is a check that finds out if there is already this user in the database or not, if not, then create a new row, if there is, then update messages for this user.
What I accept in the request: phone, message
I do not quite understand how to implement it.
UserController
#RestController
#RequestMapping("/users")
public class UserController {
#Autowired
private UserRepo userRepo;
#PostMapping(consumes = {MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE})
public String createUser(#Valid #RequestBody User requestUserDetails) {
userRepo.save(requestUserDetails);
return "The message delivered.";
}
}
User
#Entity
#Table(name = "ApiTable", schema = "TestApi")
public class User {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private Integer id;
private String phone;
private String message;
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getMessage() {
return message;
}
public void setLastName(String message) {
this.message = message;
}
}
UserRepo
public interface UserRepo extends CrudRepository<User, Long> {
}
Application
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
KeyUser
public class KeyUser implements Serializable {
private String phone;
private String message;
}
Application
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Well, the userRepo.save(requestUserDetails) already do it for you.
Look at the implementation of save method in SimpleJpaRepository<T, ID> class from Spring.
SimpleJpaRepository.java
#Transactional
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
org.springframework.data.jpa.repository.support.SimpleJpaRepository<T, ID> implements the JpaRepository<T, ID>, which is inherited by CrudRepository<T, ID>.
This already check if the object already exists on the database. All you have to supply is your entity with the primary key populated.
If the primary key is not populated, then Spring can't check if the object exists. So a new row will be created.
If the object already exists, it will call EntityManager.merge if not, it will call EntityManager.persist.
Take a look:
User use = new User();
user.setId(1);
user.setPhone("123");
user.setMessage("Hello");
userRepository.save(user);
In this case, if the User with id == 1 exists on the the database, it's information will be merged.
Now, if, for some reason, this don't fit for you, then you will have to do it manually, by searching for the user by it's ID and then applying some rule to it.
Something like this:
#RestController
#RequestMapping("/users")
public class UserController {
#Autowired
private UserRepo userRepo;
#PostMapping(consumes = {MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE})
public String createUser(#Valid #RequestBody User requestUserDetails) {
User user = requestUserDetails;
if(requestUserDetails.getId() != null) {
Optional<User> userOpt = userRepo.findById(requestUserDetails.getId());
if (userOpt.isPresent()) {
user = userOpt.get();
// the user exists... do something..
}
}
// at the end, save the user anyway (event if it exists or not)
userRepo.save(user);
return "The message delivered.";
}
}
to update the object you can use the merge method. If the object has the id attribute, use merge, else, save.
Using neo4j-ogm, I writed the followed code:
The Configuration:
#Configuration
#EnableNeo4jRepositories(basePackages="com.neo4j.demo.repositories")
#EnableTransactionManagement
#ComponentScan("com.neo4j.demo")
public class Neo4jApplication extends Neo4jConfiguration{
#Bean
public SessionFactory getSessionFactory(){
return new SessionFactory("com.neo4j.demo.domain");
}
#Bean
public Neo4jServer neo4jServer(){
return new RemoteServer("http://username:password#localhost:7474","neo4j","neo4jhello");
}
#Bean
#Scope(value="session",proxyMode=ScopedProxyMode.TARGET_CLASS)
public Session getSession() throw Exception{
return super.getSession();
}
}
The NodeEntities:
#NodeEntity
public class Message {
#GraphId
Long nodeId;
#Index(unique=true)
String id;
Person author;
#Relationship(type="LISTENER")
List<Person> listeners;
//getters and setters
}
#NodeEntity
public class Person{
#GraphId
Long nodeId;
#Index(unique=true)
String id;
String name;
//getters and setters
}
When I use session.save to save the new instance of the Message, it works well. All of the related entities are saved. But the session.load seems work not well
List<Message> messages = session.loadAll(Message.class,N)
where the N is [-1,3], the results are same. The properties, such as author, listeners are null. Why?
I am developing a java-spring project and I have a packagegr.serafeim.domain which contains all my domain classes (for instance, Student, School etc - they are concrete classes). All these have relations between them through JPA annotations. Until now everything was fine, but now I need to implement methods to these classes that would need to query the database to get their results.
How should I implement these methods ? My first choice would be to put it inside the domain classes, however in order to do that I'd need to include references to the data repositories in all my domain classes. I don't like this very much -- is this a good design choice ? Should I implement interfaces that my domain classes would implement ? Can you propose a better solution -- what is the common practice in such cases ?
TIA
My answher: no, don't place references to repositories into you domain models. Place them into business services instead. And don't manage any security into domain at all. Security is refered to use cases, not domain logic, so security is placed over domain.
And I disagree with Sandhu. I'd use the following architecture:
Model classes. They don't get getters/setters for everything. It depends on model logic. Otherwise you get model where you can easily break consistency. Or where are many unobvious things. Suppose you have User.registrationDate field. When you construct a new User object, you should not forget to field registrationDate field by hands. So, just place registrationDate initialization in your constructor and remove setter!
Repository interface just inside your model. Suppose you have some business logic that depends on existing stored objects. You can't expliciltly refer from your domain logic into infrastructure dependencies like JPA, Hibernate, JDBC, etc. So you query this stored objects from interfaces.
Business services (optionally). They implement some complex logic, involving many different entities, not including security and transaction management. Your question is about it. Yes, if you need query for entities in your domain logic, place query into repository and call it from your business service.
Repository implementation inside infrastructure package. Implements repository interfaces using JPA or mockito or whatever else. They also don't include neither security nor transactions.
Application services (optionally). If there is some complex interaction with infrastructure or security checking.
Remote facade interface. Client and server communicate only through remote facade interface.
Remote facade implementation (controller). Transforms thick entity objects into thin DTOs (data transfer objects). All transaction demarcation and security is here (often using annotations).
This approach conforms DDD style, described by Martin Fowler. I think that JPA is musused in most of modern projects. It is used not as persistence provider, but as active record. Active record is not domain model implementation pattern, but database abstraction pattern. So if you really want transaction script approach, use some active record library or something like MyBatis instead of heavyweight JPA provider.
Also I don't understand the need of DAO. JPA providers do data abstraction themselves, don't they? Also data abstraction is not about model, but about infrastructure. So why is DAO placed over model? If you do really need DAO, you should place it under model (into repository implementation, I suppose).
Example of right usage:
package my.example.model;
#Entity
public class User {
#Id
#GeneratedValue
private Integer id;
private String login;
private String password;
#Temporal(TemporalType.TIMESTAMP)
private Date registrationDate;
User() {
// for persistence provider only
}
public User(String login, String password) {
this.login = login;
this.password = hashPassword(password);
this.registrationDate = new Date();
}
public String getLogin() {
return login;
}
public String setPassword(String password) {
this.password = hashPassword(password);
}
public boolean matchPassword(String password) {
return this.password.equals(hashPassword(password));
}
public Date getRegistrationDate() {
return registrationDate;
}
private static String hashPassword(String password) {
try {
MessageDigest digest = MessageDigest.getInstance("sha-1");
StringBuilder sb = new StringBuilder();
byte[] bytes = digest.digest(password.getBytes(charset));
for (byte b : bytes) {
sb.append(Character.forDigit((b >>> 4) & 0xF, 16)).append(Character.forDigit(b & 0xF, 16));
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
}
}
package my.example.model;
public interface UserRepository {
User findByLogin(String login);
User findBySurrogateId(int id);
Integer getSurrogateId(User user);
boolean contains(User user);
void add(User user);
void delete(User user);
}
package my.example.infrastructure;
#Component
public class PersistentUserRepository implements UserRepository {
#PersistenceContext
private EntityManager em;
public void setEntityManager(EntityManager em) {
this.em = em;
}
#Override public User findByLogin(String login) {
// I'd use QueryDSL here
QUser qusr = new QUser("usr");
return new JPAQuery(em)
.from(qusr)
.where(qusr.login.eq(login))
.singleResult(qusr);
}
#Override public User findBySurrogateId(int id) {
return em.find(User.class, id);
}
#Override public Integer getSurrogateId(User user) {
return (Integer)em.getEntityManagerFactory().getPersistenceUnitUtil().getIdentity(user);
}
#Override public boolean contains(User user) {
return em.contains(user);
}
#Override public void add(User user) {
em.persist(user);
}
#Override public void delete(User user) {
em.remove(user);
}
}
package my.example.facade;
public interface UserRemoteFacade {
UserDTO getUser(String login);
UserDTO getUser(int id);
void changePassword(int userId, String newPassword);
void registerUser(String login, String password) throws LoginOccupiedException;
boolean authenticate(String login, String password);
}
package my.example.facade;
public class UserDTO implements Serializable {
private int id;
private String login;
private Date registrationDate;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public Date getRegistrationDate() {
return registrationDate;
}
public void setRegistrationDate(Date registrationDate) {
this.registrationDate = registrationDate;
}
}
package my.example.server;
#Transactional #Component
public class UserRemoteFacadeImpl imlements UserRemoteFacade {
private UserRepository repository;
private Security security;
#Autowired
public UserRemoteFacadeImpl(UserRepository repository, Security security) {
this.repository = repository;
this.security = security;
}
#Override public UserDTO getUser(String login) {
return mapUser(repository.findByLogin(login));
}
#Override public UserDTO getUser(int id) {
return mapUser(repository.findBySurrogateId(id));
}
private UserDTO mapUser(User user) {
if (user != security.getCurrentUser()) {
security.checkPermission("viewUser");
}
UserDTO dto = new UserDTO();
dto.setId(repository.getSurrogateId(user));
dto.setLogin(user.getLogin());
dto.setRegistrationDate(user.getRegistrationDate());
return dto;
}
#Override public void changePassword(int userId, String newPassword) {
User user = repository.findByLogin(login);
if (user != security.getCurrentUser()) {
security.checkPermission("changePassword");
}
user.setPassword(newPassword);
}
#Override public void registerUser(String login, String password) throws LoginOccupiedException {
if (repository.findByLogin(login) != null) {
throw new LoginOccupiedException(login);
}
User user = new User(login, password);
repository.add(user);
}
#Override public boolean authenticate(String login, String password) throws LoginOccupiedException {
User user = repository.findByLogin(login);
return user != null && user.matchPassword(password);
}
}
Also see this project: http://dddsample.sourceforge.net/
The best way to implement Spring is to have the following components in your project:
Model Classes (#Entity)- Exactly your domain classes
Dao Interfaces
Dao Implemetations (#Repository)
Service Interfaces
Service Implementations (#Service)
Controller classes (#Controller)
2 & 3 forms the Persistence Layer and 4 & 5 forms the Service Layer
Example:
Model class
#Entity
public class User implements Serializable {
private static final long serialVersionUID = -8034624922386563274L;
#Id
#GeneratedValue
#Column(name = "id")
private int id;
#Column(name = "name")
private String name;
public int getId() {
return id;
}
public void setId(final int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
}
Dao Interface
public interface UserDao {
public User getUser(String username);
}
Dao Implementation
#Repository
public class UserDaoImpl implements UserDao {
#Autowired
private SessionFactory sessionFactory;
private Session openSession() {
return sessionFactory.getCurrentSession();
}
#Override
public User getUser(String username) {
List<User> userList = new ArrayList<User>();
Query query = openSession().createQuery(
"from User u where u.username = :username");
query.setParameter("username", username);
userList = query.list();
if (userList.size() > 0)
return userList.get(0);
else
return null;
}
}
Service Interface
public interface UserService {
public User getUser(String username);
}
Service Implementation
#Service
#Transactional
public class UserServiceImpl implements UserService {
#Autowired
private UserDao userDao;
#Override
public User getUser(final String username) {
return userDao.getUser(username);
}
}
I am trying to take a value from one managed bean to another. I have a loginbean which gets the username and I need to take that value and put it into another managed bean sidebarbean. I am using JSF and thought i could go something like
#{sidebarbean.setUserName(loginbean.username)} but this does not work. Any suggestions?
Following your suggestion
#ManagedBean(name = "sidebarbean")
#SessionScoped
public class SideBarBean {
private ArrayList myContacts = new ArrayList();
private String user;
#PersistenceContext
private EntityManager em;
#Resource
private UserTransaction utx;
public SideBarBean() {
}
public ArrayList getMyContacts() {
myContacts.clear();
List<Contacts> list = em.createNamedQuery("Contacts.findByUsername")
.setParameter("username", user).getResultList();
for (Contacts c : list) {
myContacts.add(c.getContact());
}
return myContacts;
}
public void setMyContacts(ArrayList myContacts) {
this.myContacts = myContacts;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
}
#ManagedBean(name = "loginbean")
#SessionScoped
public class LoginBean {
#PersistenceContext
private EntityManager em;
#Resource
private UserTransaction utx;
#ManagedProperty(value="#{sidebarbean}")
private SideBarBean sbb;
private String username;
private String password;
private Boolean verified = false;
private Boolean authFail = false;
public LoginBean() {
}
public void update(){
sbb.setUser(username);
}
I get "Unable to create managed bean loginbean. The following problems were found: - Property sbb for managed bean loginbean does not exist. Check that appropriate getter and/or setter methods exist."
You can use #ManagedProperty annotation then you can access to same instance of SideBarBean.
#ManagedBean(name="loginbean")
public class LoginBean{
#ManagedProperty(value="#{sidebarbean}")
private SideBarBean sidebarbean;
public void update(){
sidebarbean.setUserName("xxxx");
}
}