I'm trying to create a simple login based on the Zentask sample, however I'm getting a runtime exception in smgts2\app\controllers\Application.java at line 43.
public static Result authenticate() {
Form<Login> loginForm = form(Login.class).bindFromRequest(); //Line 43
if(loginForm.hasErrors()) {
return badRequest(login.render(loginForm));
} else {
session("user_name", loginForm.get().user_name);
return redirect(
I've uploaded the files in github: https://github.com/gscruz/smgts2-start
Looking at your project on GitHub, I think the main issues are with the JPA annotations on your Accounts model class that models your user_account database table. The mappings on your model class get exercised when you bind the form data to a Login object, since Login.validate queries user_account.
Since the name of your class does not match the name of the table, you'll need a JPA #Table annotation to explicitly state the mapping:
#Entity
#Table(name = "user_account")
public class Accounts extends Model
You'll also need #Column annotations for the fields whose names don't match up with their corresponding columns. Give that a go and see if it gets you any further.
Related
I've heard when you want to return some object from a service method, you have to define a DTO object (or POJO object generated with JSON Schema) instead of using an Entity.
To make it clear, here is the example:
We have an entity and a jpa repository for it:
#Data
#Entity
#Table(name = "tables")
public class Table {
#Id
private Long id;
private String brand;
}
This is a bad practice:
#Service
public class MyService {
#Autowired
private TableRepository tableRepository;
#Transactional
public Table create() {
Table table = new Table();
// Some logic for creating and saving table
return table;
}
}
This is a good practice:
#Service
public class MyService {
#Autowired
private TableRepository tableRepository;
#Transactional
public TableDTO create() {
Table table = new Table();
// Some logic for creating and saving table
// Logic for converting Table object to TableDTO object
return tableDTO;
}
}
Why is this so?
Thank you!
Probably you mean a DTO (Data Transfer Object), not DAO (Data Access Object). Let me clarify this:
Data Transfer Object:
A Pojo that represents a piece of information. Usually it has aggregated data in it.
Data Access Object:
An object that performs access to some kind of persistence storage for retrieving information, someone considers it a synonim of Repository, someone not.
Entity:
An object that represents data that has been retrieved from the database.
Why is returning an Entity from the Service considered a bad practice?
The reason is that the Entity is something that is very close to the database. It contains primary key, someone could guess your database structure from it and the set of the data in case of query can be verbose. Hence, it is preferable to have some kind of logic, usually a mapper, that hides primary key and aggregates data to be less verbose and to not expose the db structure. Also, while the Entity is built on the table structure, the DTO can be customized in base of caller needs. Usually it contains exactly the data that is needed for some action and nothing more than this. Suppose you have thirdy party software that calls your backend services: you should not expose the db structure (Entities) to this service. It is better to define a contract, with the minimal information needed for this thirdy party service to operate, and expose only this part of the information, hiding all the rest.
Hope that's a little bit more clear now.
Edit:
Of course there are other good reasons for using DTOs instead of Entities, this is only an introductory explanation to the subject.
I looked for countless questions.
But most of the questions were as follows.
Entity -> Dto
Entity and Dto have the same attribute value.
but I don't want this.
I wonder how I can convert Dto to Entity when if property value present in Entity did not exist in Dto.
Some Code
dosen't specify the codes for the [annotations, Lombok, jpa, ...etc]
but it exists!
User Entity
class User {
Long id,
String username,
String email,
String password
}
UserDto
class UserDto {
String email
}
Post Entity
class Post {
Long id,
String title,
User user
}
PostDto
class PostDto {
Long id,
String title,
String username
}
UserService
...
UserDto findUser(id: Long) {
...
}
...
PostService
...
PostDto savePost(Post post) {
...
}
...
PostController
...
PostDto createPost(#RequestBody PostDto postDto) {
// spring security
Long userId = XXX.getUserId()
....
UserDto userDto = userService.findUser(userId)
// HERE !! what can i do ??
// How can i convert userDto to user ?
Post post = new Post(postDto.title, user)
PostDto newPost = postService.savePost(post)
}
...
Question
All methods of userService return in DTO.
how can I set user entity in Post Entity?
I received a userDto return which has only username.
What should I do at times like this?
The repository is not being called directly from the controller.
The service would like to return the DTO unconditionally.
Should I create an additional Dto that has the same properties as user entity?
Normally I implemented my class in following manner,
Entity : Contain all data related to your actual database object. (Additional data by #transient annotation)
DTO : Customize class which creates to provides compatibility between Entity and required JSON.
Mapper : It can convert Entity to DTO and vice versa.
In sort, Create entity for database object, n numbers of DTO for verity of need and using mapper class convert it to appropriate type and write this terms in your service class. So based on your need create DTO and in service class implement logic for get them all together.
(In best way use interface or inheritance when wants to bind multiple DTO in single entity or scattered it.)
Now comes to your question,
I wonder how I can convert DTO to Entity when if property value present in Entity did not exist in DTO.
Answer : Convert it using Mapper class. As per I define above Entity is database object and DTO is expected JSON. So doesn't matter it compulsory exist in your DTO. You can customize DTO as per your need.
The repository is not being called directly from the controller.
Answer : As obvious you have to do that and right way to implementation.
Should I create an additional DTO that has the same properties as user entity?
java
Answer : Yes you can but if it compulsory required. My suggestion is follow structure as I defined earlier it becomes helpful in future also, Suppose new kind of data you need you just have to add one function in mapper class and it return data accordingly, you also modify from single place and use every where.
This suggestion for based your code.
Move your all logical code controller to service class
In service class fire query and contain data of userDTO.
UserDto userDto = userService.findUser(userId)
It gives you email. Based on this fire another query for fetch user.
My personal suggestion as developer,
Create one JHipster project once and check their flow it gives you good idea regarding how to create structure in professional way.
I have a next problem: I ve got a several tables in database, and somehow i need to make a query from one of them, but only in runtime i will know the name of needed table, so is any possibility to pass table name to #Table annotation of entity in runtime? All of these tables have absolutely identical schema. The only distinction - is name (BILLING_DATA_2016_1, BILLING_DATA_2015_12 etc.). Do somebody have an idea how can i pass the name of table dynamically? Or may be some hack with Queries and Inheritance?
You can try HibernateInterceptor. Place the {BILLING_DATA_PLACEHOLDER} string into your #Table annotation and just replace it on fly
public class HibernateInterceptor extends EmptyInterceptor {
#Override
public String onPrepareStatement(String sql) {
String prepedStatement = super.onPrepareStatement(sql);
prepedStatement = prepedStatement.replaceAll("{BILLING_DATA_PLACEHOLDER}", theRealSchemaName);
return prepedStatement;
}
}
Have not tried though
I have a User object mapped with hibernate annotations working just fine.
Eg
#Entity
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long userId;
etc ..
}
I then have a "Add User" form using Spring 3 MVC and I required a command object to back this form, so I subclassed User from above in UserCommand. The UserCommand has some extra stuff on it related to the web interface etc that doesn't need to be saved as part of a User entity.
Eg
public class UserCommand extends User {
private String initialAddress;
etc
}
So my view/presentation layer basically creates a UserCommand object, fills out the user details and then the controller submits this down to the service/dao layer to persist. Since UserCommand extends ("is-a") User the dao accepts the UserCommand instance and it passes the dao validation checks (eg ensure has username and password filled out).
However when hibernate actually comes to persist the object as an entity in the db, it seems to realise the actual object is a UserCommand, which isn't a mapped entity, even though it's super type is.
The resulting error is;
org.hibernate.MappingException: Unknown entity: com.example.UserCommand
org.hibernate.impl.SessionFactoryImpl.getEntityPersister(SessionFactoryImpl.java:691)
org.hibernate.impl.SessionImpl.getEntityPersister(SessionImpl.java:1494)
org.hibernate.engine.ForeignKeys.isTransient(ForeignKeys.java:202)
org.hibernate.event.def.AbstractSaveEventListener.getEntityState(AbstractSaveEventListener.java:531)
org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:102)
org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61)
org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:808)
org.hibernate.impl.SessionImpl.persist(SessionImpl.java:782)
org.hibernate.impl.SessionImpl.persist(SessionImpl.java:786)
Is there a way around this issue? I seemed like an obvious thing to do, the form is filling out a User so just use an extension of User (ie UserCommand) as the form's backing command object.
Or am I going to have to break the inheritance, duplicate User's fields in UserCommand and the explicitly copy all the values from UserCommand into User during the form submit?
I think mixing database and view entities is a bad practice. These are different layers and they should operate on different DTOs. Usually I use following pattern to convert between two layers:
public class UserCommand {
public static UserCommand fromUser(User user) {
UserCommand command = new UserCommand();
// fill UserCommand fields
return command;
}
public void toUser(User user) {
// fill User fields
}
}
If conversion between view and database DTOs require some complex logic you can move these methods to conversion service.
One benefit from splitting these entities is validation. You can specify JSR-303 annotations to validate these beans and in most cases they will be different for UI and DB.
Agreed with Hoaz. If you want to copy each field of your object from DTO to DB easily you can use the Dozer utility.
I just ran into this issue myself for Hibernate 3.6 you can explicitly define a subclass.
http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/mapping.html
With xml you could:
<subclass name="DomesticCat"
discriminator-value="D">
<property name="name" type="string"/>
</subclass>
or with Annotation:
#Entity #DiscriminatorValue("D")
public class DomesticCat extends Cat {
//class implementation here
}
EDIT:
Don't forget the descriminator.
<discriminitor insert="false" formula="'C'" />
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(discriminatorType=DiscriminatorType.STRING, insert=false)
#DiscriminatorFormula("'C'")
#DiscriminatorValue("C")
public class Cat { ... }
In our company we have a strange database model which can't be modified because to many systems works with them. Up to know we have a straight java application which connects with hibernate to the database and loads the data. We have for each table one xml mapping file.
The strange thing about the database is that we do not have any primary keys. Most table have a unique index containing several columns.
Now we want to use an application server (jboss) and the ejb model. So I created a class like this:
#Entity
#Table (name = "eakopf_t")
public class Eakopf implements Serializable {
#Embeddable
public static class EakopfId implements Serializable {
private String mandant;
private String fk_eakopf_posnr;
// I removed here the getters and setters to shorten it up
}
#Id
private EakopfId id;
private String login;
// I removed the getters and setters here as well
}
This works perfect.
Because our customers have different versions of the database schema I thought about extending this class on each database release change. So each interface we create with java can decide which version of the table will be used.
Here is the extended table class
#Entity
#Table (name = "eakopf_t")
public class Eakopf6001 extends Eakopf implements Serializable {
private String newField;
// getters and setters
}
If I use Eakopf (the base version) it is working if I do something like that:
EakopfId id = new EakopfId();
id.setMandant("001");
id.setFk_eakopf_posnr("ABC");
Eakopf kopf = (Eakopf) em.find(Eakopf.class, id);
But if I do this:
EakopfId id = new EakopfId();
id.setMandant("001");
id.setFk_eakopf_posnr("ABC");
Eakopf6001 kopf = (Eakopf6001) em.find(Eakopf6001.class, id);
this exception occues
javax.ejb.EJBException: javax.persistence.PersistenceException:
org.hibernate.WrongClassException: Object with id:
de.entity.Eakopf$EakopfId#291bfe83 was not of the specified subclass:
de.entity.Eakopf (Discriminator: null)
Does anybody has an idea?
many greetings,
Hauke
Doing what you did means to Hibernate that you're storing two different kinds of entities in a single table. This is possible is you use a discriminator column. But if I understand correctly, you just want one kind of entity in the table : Eakopf6001. In this case, its base class should be annotated with #MappedSuperClass, not with #Entity.
I would suggest creating a class annotated with #MappedEntity (let's call it BaseEakopf), and two entities: EaKopf and EaKopf6001, each with their set of additional fields. Include one of the other of the entities in the list of mapped classes, depending on which one you want to use.
My personal opinion is that if you have multiple versions of your app, they should use the same entities, but with different fields. Your version control system would take care of these multiple versions, rather than your source code (i.e. have one set of source files per version of the app, rather than one single set of source files for all the possible versions).