存储库与 DAO(再次) [英] Repository vs. DAO (again)

查看:60
本文介绍了存储库与 DAO(再次)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In general this back-story does not matter but just to explain the code below:

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

The server handles users and user groups. User groups are able to "discover" places - at this point in time these places are coming exclusively from the Google Places API.

目前,我的服务层中有很多 JpaRepository 对象,我称之为 Repository.我强调Repository",因为在我下面提出的解决方案中,它们会降级为 DAO.

Currently, I have a lot of JpaRepository objects, which I call Repository, in my Service Layer. I am stressing "Repository" because in my proposed solution below, they'd be downgraded to DAOs.

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

However, what I do not like in my current code, and also the reason for my question here, is the amount of repositories one can find in the 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:


A Solution That Does Not Work


What could make this code a lot simpler and had the potential to resolve this mess up there, would be @Inheritance:

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

@Entity
@Table(name = "google_place")
public class GooglePlace extends Place { /* .. */ }

然而,这不是一个选项,因为那样我就不能有一个 PlaceRepository 来保存一个地方.Hibernate 似乎不喜欢它..

However, this is not an option because then I cannot have a PlaceRepository which saves just a place. Hibernate does not seem to like it..

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

I think my confusion starts with the names that Spring is using. E.g. JpaRepository - I am not so sure if this is actually "the right" name. Because as far as I understood, these objects actually work like data access objects (DAOs). I think it should actually look something like this:

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..
    }

}

<小时>

总结

<小时>

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


Summary


I would like to know what I don't see. Am I fighting the framework, or does my data model not make sense and this is why I find myself struggling with this? Or am I still having issues on how the two patterns "Repository" and "DAO" are supposed to be used?

如何实现这一点?

推荐答案

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

I would say you are correct that there are too many repository dependencies in your service. Personally, I try to keep the number of @Autowired dependencies to a minimum and I try to use a repository only in one service and expose its higher level functionality via that service. At our company we call that data sovereignty (in German: Datenhoheit) and its purpose is to ensure that there is only one place in the application where those entities are modified.

根据我从您的代码中了解到的,我将引入一个 PlacesService,它具有 PlaceRepositoryGooglePlaceRepository 的所有依赖项GooglePlaces.如果您觉得 Service 不是正确的名称,您也可以将其称为 PlacesDao,用 Spring @Component 注释标记它并注入所有Repositories,顾名思义就是事物的集合

From what I understand from your code I would introduce a PlacesService which has all the Dependencies to the PlaceRepository, GooglePlaceRepository and GooglePlaces. If you feel like Service is not the right name you could also call it the PlacesDao, mark it with a Spring @Component annotation and inject all the Repositories, which are by definition collections of things

@Component
public class PlacesDao {

    @Autowired
    private PlaceRepository placeRepository;

    @Autowired
    private GooglePlaceRepository googlePlaceRepository;

此服务/DAO 可以提供 API findPlacesForGroup(userGroup)createNewPlace(...),从而使您的 for 循环更小更优雅.

This service/DAO could offer an API findPlacesForGroup(userGroup) and createNewPlace(...) and thus making your for Loop smaller and more elegant.

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

On a side note: you can merge your first four lines into just one. Java Optionals support a orElseThrow() method:

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

这篇关于存储库与 DAO(再次)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆