如何解决Java模型休眠映射问题
注意:我使用Spring Data Jpa来保持持久性。
问题:
我有一个用户拥有的徽章列表,作为 User 类中的数据成员。 我也有用户作为徽章类(即徽章的创建者)中的数据成员
我想在用户和徽章列表数据成员之间建立关系。 关系的类型为OnetoMany(即,一个用户将拥有许多徽章),反之亦然。
我希望它以这种方式工作, 在代码中,
当我将发布者(又名“用户”)设置为特定用户对象的情况下保存徽章对象时,则无需将其(徽章)添加到该用户拥有的徽章列表中。
我尝试创建关系,但是它在REST API响应中返回了用户拥有的徽章的空列表。
徽章模型
import javax.persistence.*;
@Entity
@Table(name = "badges")
public class Badge {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "badge_id")
private int mId;
@Column(name = "badge_name",nullable = false,unique = true)
private String mName;
@Column(name = "badge_description")
private String mDescription;
@Lob
@Column(name = "badge_logo",nullable = false)
private String mlogo;
@ManyToOne
@JoinColumn(name = "issuer_id")
private User mIssuer;
}
用户模型
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "users")
public class User {
@Id@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "user_id")
private long mId;
@Column(name = "username",unique = true)
private String mUserName;
@Column(name = "fullname",nullable = false)
private String mFullName;
@Column(name = "salt")
private String mSalt;
@OnetoMany(mappedBy = "mIssuer",cascade = CascadeType.ALL)
private List<Badge> mOwnedBadges;
@OnetoMany
@JoinColumn(name = "received_badges_id")
private List<Badge> mReceivedBadges;
}
CommandLineRunner
import com.badging.spinnerbadger.SpinnerBadger.Models.Badge;
import com.badging.spinnerbadger.SpinnerBadger.Models.User;
import com.badging.spinnerbadger.SpinnerBadger.Services.Intefaces.BadgeSerivce;
import com.badging.spinnerbadger.SpinnerBadger.Services.Intefaces.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Component
public class StartupExecutor implements CommandLineRunner {
@Autowired
private BadgeSerivce mBadgeSerivce;
@Autowired
private UserService mUserService;
@Override
public void run(String... args) throws Exception {
//Todo:: issuer cannot issue badge to itself
final User user1 = new User();
user1.setFullName("User1 FullName");
user1.setSalt("salt1");
user1.setUserName("User1 UserName");
mUserService.save(user1);
final User user2 = new User();
user2.setFullName("User2 FullName");
user2.setSalt("salt2");
user2.setUserName("User2 UserName");
mUserService.save(user2);
Badge badge1 = new Badge();
badge1.setDescription("Desc1");
badge1.setlogo("logo1");
badge1.setName("Badge1");
badge1.setIssuer(user1);
mBadgeSerivce.save(badge1);
Badge badge2 = new Badge();
badge2.setDescription("Desc2");
badge2.setlogo("logo2");
badge2.setName("Badge2");
badge2.setIssuer(user2);
mBadgeSerivce.save(badge2);
Badge badge3 = new Badge();
badge3.setDescription("Desc3");
badge3.setlogo("logo3");
badge3.setName("Badge3");
badge3.setIssuer(user1);
mBadgeSerivce.save(badge3);
user1.setReceivedBadges(Arrays.asList(badge2));
user2.setReceivedBadges(Arrays.asList(badge1,badge3));
}
}
注意:它也不会保存用户的“已接收徽章”列表,如果您也能确定这一点,那么我将非常感谢您。
BadgeRepo
import com.badging.spinnerbadger.SpinnerBadger.Models.Badge;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface BadgeRepo extends PagingAndSortingRepository<Badge,Long> {
}
UserRepo
import com.badging.spinnerbadger.SpinnerBadger.Models.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepo extends JpaRepository<User,Long> {
}
BadgeServiceImpl
package com.badging.spinnerbadger.SpinnerBadger.Services.Implentations;
import com.badging.spinnerbadger.SpinnerBadger.Repository.BadgeRepo;
import com.badging.spinnerbadger.SpinnerBadger.Models.Badge;
import com.badging.spinnerbadger.SpinnerBadger.Services.Intefaces.BadgeSerivce;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class BadgeServiceImpl implements BadgeSerivce {
@Autowired
private BadgeRepo mBadgeRepo;
@Override
public List<Badge> getAllBadges(int pageNumber,int sizeOfPage) {
if (sizeOfPage > 20) {
sizeOfPage = 20;
}
final Page<Badge> allPages = mBadgeRepo.findAll(PageRequest.of(pageNumber,sizeOfPage));
if (allPages.getTotalElements() > 0) {
return allPages.toList();
} else{
return new ArrayList<Badge>();
}
}
@Override
public void save(Badge badge) {
mBadgeRepo.save(badge);
}
}
UserServiceImpl
import com.badging.spinnerbadger.SpinnerBadger.Models.Badge;
import com.badging.spinnerbadger.SpinnerBadger.Models.User;
import com.badging.spinnerbadger.SpinnerBadger.Repository.UserRepo;
import com.badging.spinnerbadger.SpinnerBadger.Services.Intefaces.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepo mUserRepo;
@Override
public void save(User user) {
mUserRepo.save(user);
}
@Override
public List<Badge> getUsersReceivedBadgeList(long userId) {
final Optional<User> byId = mUserRepo.findById(userId);
return byId.orElse(new User()).getReceivedBadges();
}
@Override
public List<Badge> getUserOwnedBadgeList(long userId) {
final Optional<User> byId = mUserRepo.findById(userId);
return byId.orElse(new User()).getReceivedBadges();
}
}
由Hibernate生成的sql ->用户模型第一,徽章模型第二
Hibernate: insert into users (fullname,salt,username,user_id) values (?,?,?)
Hibernate: insert into badges (badge_description,issuer_id,badge_logo,badge_name,badge_id) values (?,?)
解决方法
我在这里看到了几处可能出错的地方。
-
您似乎没有指定交易。将
@Transactional
添加到应参与事务的bean或方法中。至少应包括(最终)修改数据库的所有内容,即修改托管实体的任何语句,包括从数据库和save
语句中加载该语句的语句。我希望这是您遇到的问题的真正原因。 -
您似乎没有适当的代码来同步双向关系的双方。所以,当你打电话
badge1.setIssuer(user1)
,user1
不会更新,因此如果您致电user1.getOwnedBadges()
仍然会返回不变的(空)值。在这种情况下,我怀疑这是一个问题,但这会导致 一次交易中看起来不同的关系, 取决于您从哪一侧看。并更改为 非拥有方(在您的情况下为
User
)将不会持续存在。所以应该解决 无论如何。另请参见https://vladmihalcea.com/jpa-hibernate-synchronize-bidirectional-entity-associations/ -
保存实体时,应使用
save
方法返回的实例,而不要使用传递给save
作为参数的实例。通常它们是相同的,但是当它们不修改传递给save
的那个时,可能不会导致状态持久化到数据库。
如果这些问题已解决且问题仍然存在,我建议以下内容收集有关发生的情况的更多信息:
-
激活logging of SQL statements including parameters以便查看实际保留的内容(以及时间)。
-
创建一个JUnit测试来测试您的服务。这样可以更清楚地了解实际执行的操作,并允许创建要比较的变体。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。