Mukhamedali  Zhadigerov
Mukhamedali Zhadigerov

Reputation: 861

Detach entity in Spring Data

I'm using Spring Data and i have such class structure:

A has-a B  and  B has-a List<C>

and code:

List<A> aList= aRepository.findAll();
aList.forEach(a-> a.getB().setC(null));

I don't need List of C's in frontend (in this particular scenario). But when I set C as null, the EntityManager is not in detached state and it sets C as null in the database. How to detach entities in a List after I retrieve them? I tried this:

EntityManager em=entityManagerFactory.createEntityManager();
aList.forEach(a -> em.detach(a) ......);

But it didn't work. Any suggestions?

EDIT:

Here's the actual entities (without unnecessary fields):

Session (Class A in above example):

@Entity
public class AuthSession {
    private AuthUser user;

    @ManyToOne
    @JoinColumn(name = "user_id",foreignKey = @ForeignKey(name = "fk_auth_user_id"))

    public AuthUser getUser() {
        return user;
    }

    public void setUser(AuthUser user) {
        this.user = user;
    }
}

User (class B in above example):

@Entity
public class AuthUser {

    private Set<AuthRole> roles;

    @ManyToMany
    @JoinTable(
        name = "USER_ROLE_LINK", 
        schema = "iapauth", 
        joinColumns = @JoinColumn(name = "user_id"), 
        foreignKey = @ForeignKey(name = "fk_user_id"), 
        inverseJoinColumns = @JoinColumn(name = "role_id"), 
        inverseForeignKey = @ForeignKey(name = "fk_role_fk"))
    public Set<AuthRole> getRoles() {
        return roles;
    }

    public void setRoles(Set<AuthRole> roles) {
        this.roles = roles;
    }

Role (Class C in above example):

@Entity
public class AuthRole{}

I have a code to add roles to user (new entries in auto-generated link-table "USER_ROLE_LINK"). It works fine. And i have this code to retrieve all sessions:

EntityManager em=entityManagerFactory.createEntityManager();
List<AuthSession> sessions=sessionRepo.findAll();
sessions.forEach(x->{
    em.detach(x);
    AuthUser user=x.getUser();
    if(user!=null) user.setRoles(null);
});
return sessions;

But after this code executes, entries in user-role table (those whose users are in current session) are deleted.

Upvotes: 0

Views: 5944

Answers (1)

Jens Schauder
Jens Schauder

Reputation: 81862

While the idea of detaching is a correct one, you are detaching the wrong entities.

With this code

List<AuthSession> sessions=sessionRepo.findAll();
sessions.forEach(x->{
    em.detach(x);
    AuthUser user=x.getUser();
    if(user!=null) user.setRoles(null);
});

All the AuthUsers referenced by the AuthSession are still managed by the EntityManager (i.e. not detached). You need to either explicitly detach them or add a cascade configuration to AuthSession.user

See: https://docs.oracle.com/cd/E19798-01/821-1841/bnbqm/index.html

Also as Mukhamedali Zhadigerov describes in the comments one should use an injected EntityManager.

Upvotes: 2

Related Questions