I built an application with Angular, SpringBoot and MySQL Database.
It uses CrudRepository and I don't understand it (everything is working OK).
How does the controllers/repository know which table to get the data from? I mean, I don't specify table name.
Can someone explain me how this works?
When you extend CrudRepository you define its generic type. In Here you tell from which Entity class the repository will fetch the data. And Entity classes in JPA are used to represents Tables. So thats how it knows from where to get data. for example :
public interface UserRepository extends CrudRepository<User, Long> {
}
In the code above, I specified the generic type to be User, Also User is my Entity class which represents users table in my database. So this Repository will deal with users table.
In spring boot data JPA application any model is annotated with either #Entity or along with #Table(name = "User"). In case of former, the default table name is same as Entity Name.
Also, when you create any repository like:
public interface UserRepository extends CrudRepository<User, Long> the default implementation of Entity i.e User is referred to perform all operations in generic manner.
I found the following explanation helpful since it goes through all possible combinations of #Entity and #Table and lists the corresponding query.
https://walkingtechie.blogspot.com/2019/06/difference-between-entity-and-table.html
Related
Currently, I'm learning about Spring Data JPA, and I found that I need to create a custom interface to make a custom methods. I wonder if someone can explain to me why this is so. Let's say I have entity User with fields: userId and name. Also, I have UserRepository:
public interface UserRepository extends JpaRepository<User, Long> {...}
I found that I need to make new interface - UserRepositoryCustom where I should make custom abstract methods. Also, after that, I found that I need to make class UserRepositoryImpl which implements UserRepositoryCustom. Let's take a look at the code I made:
#Repository
public class UserRepositoryImpl implements UserRepositoryCustom{
#PersistenceContext
private EntityManager entityManager;
#Override
public List<User> findUserByName(String name) {
Query query = entityManager.createNativeQuery("SELECT em.* FROM User em " +
"WHERE em.name = ?1", User.class);
query.setParameter(1, name);
return query.getResultList();
}
}
Can you please explain why I need UserRepositoryCustom and UserRepositoryImpl in foreground, And why do I need EntityManager and #PersistenceContext above it? Every piece of information is of great importance to me, because that way I will be able to extract what is most important for me, which is to understand.
I found this code, which is working fine, online, but I need to understand it.
You don't need to do this. The direct equivalent would be a method in your UserRepository interface defined as List<User> findByName(String name). You can also use JPA named queries, the #Query annotation, etc.
The usage of additional interfaces and implementation classes is intended for advanced use cases that are not (easily) possible in the queries Spring Data JPA generates for you based on method names, annotations, etc. It is not intended for easy use cases like the query you show.
And the reason why, is because that is how Spring Data JPA is designed. I highly recommend you read the full Spring Data JPA documentation. You'll notice that the solution in your question is just a minor part of the documentation, which makes clear that this is an escape hatch, not the primary way of using Spring Data JPA.
Basically I am looking for a nice mechanism to do something like
#Query(value ="generateReport", nativeQuery = true)
public void generateCSVReport(Path filename, UUID managerUuid);
where generateReport is a parametrized query located in #EnableJpaRepositories(namedQueriesLocation = "classpath:/foo/bar/file.sql)
that includes a
COPY ( SELECT * FROM foo) TO file WITH (FORMAT CSV)
Without the need of defining a Repository. Indeed I tried JpaRepository<Void,Void> but it does not work
If you don't have any entity attached to your repository then you don't really need to be implementing JpaRepository.. or even CrudRepository since it doesn't make sense for you to have any CRUD operations without an entity.
Try implementing the base interface Repository<T, ID extends Serializable> instead.
Also Repository<Void, Void> wont work since Void does not extend Serializable and also because Void is not a managed type (i.e. it is not an #Entity).
Using Spring Data repositories to do this you would have to create an empty dummy entity just to pass in. It would probably make sense to map this to the foo table you are querying in your SQL:
#Entity
#Table(name = "foo")
public class DummyEntity extends Serializable {
//Blank
}
Then extend Repository<DummyEntity, Integer>. This probably indicates that Spring Data repos aren't the best solution for this problem though.
if this question was aksed here, i surely couldnt find it, or it didnt particulary help me.
i've read some tutorials and some questions for Inheritance Mapping, which couldnt quitely solve my questions.
Say i have an abstract class :
User
And 3 more other subclasses :
UserA, UserB, UserC
those all extend User.
Every Subclass has its own table, Superclass User, meanwhile, doesn't.
In my other class Website i have a ArrayList, or should i say Collections, of Users.
The list should fetch all users of the Website.
Which strategy should i use ? I thought of MappedSuperclass, but since in my Website class the List is of User type, so am not sure what to do here.
Thanks for any help!
With JPA the Java implementation always depends on you own preferences and requirements, sometimes it is the matter of a choice.
Yes, #MappedSuperclass will do.
You can have every child with unidirectional relationship to Website. Then you gonna have Website object inside your User class (with a bunch of annotations), which will map to a database as foreign_key field (presume you are using SQL storage and 'Repositories' DAO abstraction from JPA).
It is not necessary to store a collection of users inside Website class. Just think if you really need it - it can be a mess to support consistency.
But there are cases where you need bidirectional relationship. When you store objects in memory (for caching purposes for example) you'll probably need to have this collection. In this case why not to have 'User' collection? You will fetch data through dedicated repositories(or even if you're not using those, any other way will be using 'User' tables with foreign_key, not the 'Website' table) anyway.
So, for example with the use of Spring Data JPA you can define a unidirectional relationship in a superclass and use 'repositories' next way(and bidirectional example you can find anywhere in the internet, so I am not providing it):
#Entity
public class SuperUser extends User {
...
}
#Entity
public class BasicUser extends User {
...
}
#MappedSuperclass
public abstract class User implements Serializable {
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "website_uuid", nullable = false)
protected Website website;
...
}
#Entity
public class Website implements Serializable {
...
}
#Repository
public interface SuperUserRepository extends CrudRepository<SuperUser, Long> {
Iterable<SuperUser> findByWebsite(Website website);
}
#Repository
public interface BasicUserRepository extends CrudRepository<BasicUser, Long> {
Iterable<BasicUser> findByWebsite(Website website);
}
What you are asking for seems a typical "Table-per-concrete-class" inheritance strategy. https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#entity-inheritance-table-per-class
In older version of the user guide, it has mentioned that separate table will be mapped for each non-abstract classes. In the latest document the "non-abstract" part is not mentioned but I believe it still works similarly.
So it looks something like:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
abstract class User {...}
#Entity
class UserA extends User {...}
#Entity
class UserB extends User {...}
#Entity
class UserC extends User {...}
But you should be aware of this inheritance strategy usually gives inefficient query as internally it is using union.
I'm refactoring a code base to get rid of SQL statements and primitive access and modernize with Spring Data JPA (backed by hibernate). I do use QueryDSL in the project for other uses.
I have a scenario where the user can "mass update" a ton of records, and select some values that they want to update. In the old way, the code manually built the update statement with an IN statement for the where for the PK (which items to update), and also manually built the SET clauses (where the options in SET clauses can vary depending on what the user wants to update).
In looking at QueryDSL documentation, it shows that it supports what I want to do. http://www.querydsl.com/static/querydsl/4.1.2/reference/html_single/#d0e399
I tried looking for a way to do this with Spring Data JPA, and haven't had any luck. Is there a repostitory interface I'm missing, or another library that is required....or would I need to autowire a queryFactory into a custom repository implementation and very literally implement the code in the QueryDSL example?
You can either write a custom method or use #Query annotation.
For custom method;
public interface RecordRepository extends RecordRepositoryCustom,
CrudRepository<Record, Long>
{
}
public interface RecordRepositoryCustom {
// Custom method
void massUpdateRecords(long... ids);
}
public class RecordRepositoryImpl implements RecordRepositoryCustom {
#Override
public void massUpdateRecords(long... ids) {
//implement using em or querydsl
}
}
For #Query annotation;
public interface RecordRepository extends CrudRepository<Record, Long>
{
#Query("update records set someColumn=someValue where id in :ids")
void massUpdateRecords(#Param("ids") long... ids);
}
There is also #NamedQuery option if you want your model class to be reusable with custom methods;
#Entity
#NamedQuery(name = "Record.massUpdateRecords", query = "update records set someColumn=someValue where id in :ids")
#Table(name = "records")
public class Record {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
//rest of the entity...
}
public interface RecordRepository extends CrudRepository<Record, Long>
{
//this will use the namedquery
void massUpdateRecords(#Param("ids") long... ids);
}
Check repositories.custom-implementations, jpa.query-methods.at-query and jpa.query-methods.named-queries at spring data reference document for more info.
This question is quite interesting for me because I was solving this very problem in my current project with the same technology stack mentioned in your question. Particularly we were interested in the second part of your question:
where the options in SET clauses can vary depending on what the user
wants to update
I do understand this is the answer you probably do not want to get but we did not find anything out there :( Spring data is quite cumbersome for update operations especially when it comes to their flexibility.
After I saw your question I tried to look up something new for spring and QueryDSL integration (you know, maybe something was released during past months) but nothing was released.
The only thing that brought me quite close is .flush in entity manager meaning you could follow the following scenario:
Get ids of entities you want to update
Retrieve all entities by these ids (first actual query to db)
Modify them in any way you want
Call entityManager.flush resulting N separate updates to database.
This approach results N+1 actual queries to database where N = number of ids needed to be updated. Moreover you are moving the data back and forth which is actually not good too.
I would advise to
autowire a queryFactory into a custom repository
implementation
Also, have a look into spring data and querydsl example. However you will find only lookup examples.
Hope my pessimistic answer helps :)
I create a new application with Spring and Mysql (but I am relatively free to use others things)
In this application, user logs on can not see all data (except user 'admin').
There is a tree of group, users are in group. An user can only see users (or others objects) of his group (or descendant group).
I try to find idea to do that "elegantly":
For example, if i write: productDao.findAll(), it return all product allready filtered without having rewrite all request in all DAO.
If it does not exist, I accept all kind of idea: refactoring the database? change mysql for other database, not use JPA, other.... Or may be, I'm on the wrong way and it's a bad idea to do something like that...
Use Spring Security 4. It supports Roles and Hierarchical Roles too
Use Spring Data JPA to create your DAOs. It integrates with Spring Security 4
Here's an example of writing a DAO using Spring Data JPA. You write the interface and SDJ creates the class for you.
public interface ProductRepository extends JpaRepository<Product, Long> {
#Query("select e from #{#entityName} e where e.owner = ?#{principal?.username}")
Page<Product> findAll(Pageable pageable);
}
In reality, you'd do this in your Base Repository and extend that.
You need to create a bean extending EvaluationContextExtensionSupport for the
?#{principal?.username} security expression to work