存储库与DAO(再次)



一般来说,这个背景故事并不重要,只是为了解释下面的代码:

服务器处理用户和用户组。用户组能够"发现"地点 - 目前这些地点仅来自 Google 地点 API。


当前实施情况


目前,我的服务层中有很多JpaRepository对象,我称之为存储库。我强调">存储库"是因为在下面我提出的解决方案中,它们将被降级为 DAO。

但是,我不喜欢当前代码中的内容,也是我在这里提出问题的原因,是可以在UserGroupService中找到的存储库数量。

@Service
public class UserGroupService {
private final static Logger LOGGER = LogManager.getLogger(UserGroupService.class);
@Autowired
private UserGroupRepository userGroupRepository;
@Autowired
private UserGroupPlaceRepository userGroupPlaceRepository;
@Autowired
private PlaceRepository placeRepository;
@Autowired
private GooglePlaceRepository googlePlaceRepository;
@Autowired
private GooglePlaces googlePlaces;
public UserGroupService() {
}
@Transactional
public void discoverPlaces(Long groupId) {
final UserGroup userGroup = this.userGroupRepository.findById(groupId).orElse(null);
if (userGroup == null) {
throw new EntityNotFoundException(String.format("User group with id %s not found.", groupId));
}
List<PlacesSearchResult> allPlaces = this.googlePlaces.findPlaces(
userGroup.getLatitude(),
userGroup.getLongitude(),
userGroup.getSearchRadius());
allPlaces.forEach(googlePlaceResult -> {
GooglePlace googlePlace = this.googlePlaceRepository.findByGooglePlaceId(googlePlaceResult.placeId);
if (googlePlace != null) {
return;
}
Place place = new Place();
place.setLatitude(googlePlaceResult.geometry.location.lat);
place.setLongitude(googlePlaceResult.geometry.location.lng);
place.setPlaceType(Place.PlaceType.GOOGLE_PLACE);
place.setName(googlePlaceResult.name);
place.setVicinity(googlePlaceResult.vicinity);
place = this.placeRepository.save(place);
UserGroupPlace.UserGroupPlaceId userGroupPlaceId = new UserGroupPlace.UserGroupPlaceId();
userGroupPlaceId.setUserGroup(userGroup);
userGroupPlaceId.setPlace(place);
UserGroupPlace userGroupPlace = new UserGroupPlace();
userGroupPlace.setUserGroupPlaceId(userGroupPlaceId);
this.userGroupPlaceRepository.save(userGroupPlace);
googlePlace = new GooglePlace();
googlePlace.setPlace(place);
googlePlace.setGooglePlaceId(googlePlaceResult.placeId);
this.googlePlaceRepository.save(googlePlace);
});
}
}

一个行不通的解决方案


可以使这段代码更简单并有可能解决那里的混乱,@Inheritance

@Entity
@Table(name = "place")
@Inheritance(strategy InheritanceType.JOINED)
public class Place { /* .. */ }
@Entity
@Table(name = "google_place")
public class GooglePlace extends Place { /* .. */ }

但是,这不是一种选择,因为那样我就不能有一个只保存一个地方PlaceRepository。Hibernate似乎不喜欢它。


我的提案


我认为我的困惑始于Spring使用的名称。 例如JpaRepository- 我不太确定这是否真的是"正确"的名字。因为据我了解,这些对象实际上像数据访问对象(DAO)一样工作。我认为它实际上应该看起来像这样:

public interface PlaceDao extends JpaRepository<Place, Long> {
}
public interface GooglePlaceDao extends JpaRepository<Place, Long> {
}
@Repository
public class GooglePlaceRepository {
@Autowired
private PlaceDao placeDao;
@Autowired
private GooglePlaceDao googlePlaceDao;
public List<GooglePlace> findByGroupId(Long groupId) {
// ..
}
public void save(GooglePlace googlePlace) {
// ..
}
public void saveAll(List<GooglePlace> googlePlaces) {
// ..
}
}
@Service
public class UserGroupService {
@Autowired
private GooglePlaceRepository googlePlaceRepository;
@Autowired
private UserGroupRepository userGroupRepository;
@Transactional
public void discoverPlaces(Long groupId) {
final UserGroup userGroup = this.userGroupRepository.findById(groupId).orElse(null)
.orElseThrow(throw new EntityNotFoundException(String.format("User group with id %s not found.", groupId)));

List<PlacesSearchResult> fetched = this.googlePlaces.findPlaces(
userGroup.getLatitude(),
userGroup.getLongitude(),
userGroup.getSearchRadius());
// Either do the mapping here or let GooglePlaces return 
// List<GooglePlace> instead of List<PlacesSearchResult>
List<GooglePlace> places = fetched.stream().map(googlePlaceResult -> {
GooglePlace googlePlace = this.googlePlaceRepository.findByGooglePlaceId(googlePlaceResult.placeId);
if (googlePlace != null) {
return googlePlace;
}
Place place = new Place();
place.setLatitude(googlePlaceResult.geometry.location.lat);
place.setLongitude(googlePlaceResult.geometry.location.lng);
place.setPlaceType(Place.PlaceType.GOOGLE_PLACE);
place.setName(googlePlaceResult.name);
place.setVicinity(googlePlaceResult.vicinity);
googlePlace = new GooglePlace();
googlePlace.setPlace(place);
googlePlace.setGooglePlaceId(googlePlaceResult.placeId);
return googlePlace;
}).collect(Collectors.toList());
this.googlePlaceRepository.saveAll(places);        
// Add places to group..
}
}

总结


我想知道我没有看到的东西。我是在与框架作斗争,还是我的数据模型没有意义,这就是为什么我发现自己在为此苦苦挣扎?还是我仍然对如何使用"存储库"和"DAO"两种模式有疑问?

如何实现这一点?

我会说你是对的,你的服务中有太多的存储库依赖项。就个人而言,我试图将@Autowired依赖项的数量保持在最低限度,并且我尝试仅在一个服务中使用存储库,并通过该服务公开其更高级别的功能。在我们公司,我们称之为数据主权(德语:Datenhoheit),其目的是确保应用程序中只有一个地方可以修改这些实体。

根据我从您的代码中了解到的内容,我将介绍一个具有PlaceRepositoryGooglePlaceRepositoryGooglePlaces的所有依赖项的PlacesService。如果你觉得服务不是正确的名称,你也可以称它为PlacesDao,用Spring@Component注释标记它,并注入所有存储库,根据定义,这些存储库是事物的集合

@Component
public class PlacesDao {
@Autowired
private PlaceRepository placeRepository;
@Autowired
private GooglePlaceRepository googlePlaceRepository;

此服务/DAO可以提供APIfindPlacesForGroup(userGroup)createNewPlace(...),从而使您的for Loop更小,更优雅。

附带说明:您可以将前四行合并为一行。Java 可选支持orElseThrow()方法:

UserGroup userGroup = userGroupRepository.findById(groupId).orElseThrow(() -> 
new EntityNotFoundException(String.format("User group with id %s not found.", groupId));

我认为foreach对我来说不是一个好方法。你只是为了一个职能的单一职责而做了很多事情。我会将其重构为循环的标准。

Place place = new Place();
place.setLatitude(googlePlaceResult.geometry.location.lat);
place.setLongitude(googlePlaceResult.geometry.location.lng);
place.setPlaceType(Place.PlaceType.GOOGLE_PLACE);
place.setName(googlePlaceResult.name);
place.setVicinity(googlePlaceResult.vicinity);
place = this.placeRepository.save(place);

此部分可以很容易地成为服务中的方法。

UserGroupPlace.UserGroupPlaceId userGroupPlaceId = new 
UserGroupPlace.UserGroupPlaceId();
userGroupPlaceId.setUserGroup(userGroup);
userGroupPlaceId.setPlace(place);
UserGroupPlace userGroupPlace = new UserGroupPlace();
userGroupPlace.setUserGroupPlaceId(userGroupPlaceId);
this.userGroupPlaceRepository.save(userGroupPlace);

那部分也是。

googlePlace = new GooglePlace();
googlePlace.setPlace(place);
googlePlace.setGooglePlaceId(googlePlaceResult.placeId);
this.googlePlaceRepository.save(googlePlace);

这部分:我不明白你为什么要这样做。您可以更新从存储库加载的googlePlace实例。休眠/事务将为您完成其余的工作。

相关内容

  • 没有找到相关文章

最新更新