3
\$\begingroup\$

I currently have two entities, Adress and Company. They both have DTOs to perform CRUD operations.

AddressCreateDto:

@Getter
@Setter
public class AddressCreateDto {

    @NotNull
    private String address1;

    private String address2;

    @NotNull
    private String city;

    @NotNull
    private String state;

    @NotNull
    private int zipCode;

    @JsonIgnore
    private final Long createdBy = 1L;

    @JsonIgnore
    private final Date createdDate = new Date();

    @JsonIgnore
    private final Long lastModifiedBy = 1L;

    @JsonIgnore
    private final Date lastModifiedDate = new Date();

}

CompanyCreateDto:

@Getter
@Setter
public class CompanyCreateDto {

    @NotNull
    private String name;

    @NotNull
    private AddressCreateDto address;

    @JsonIgnore
    private final Long createdBy = 1L;

    @JsonIgnore
    private final Date createdDate = new Date();

    @JsonIgnore
    private final Long lastModifiedBy = 1L;

    @JsonIgnore
    private final Date lastModifiedDate = new Date();

}

In my CompanyServiceImpl file, I am using both the CompanyRepository and the AddressRepository but I don't know if this is bad practice. The code works, but not sure if there is a better way of rewriting this so that it follows a specific set of conventions.

CompanyServiceImpl:

@Service
public class CompanyServiceImpl implements CompanyService {

    private final CompanyRepository companyRepo;

    private final AddressRepository addressRepo;

    @Autowired
    public CompanyServiceImpl(CompanyRepository companyRepo, AddressRepository addressRepo) {
        this.companyRepo = companyRepo;
        this.addressRepo = addressRepo;
    }

    @Override
    public CompanyReadDto create(CompanyCreateDto dto) {
        Address address = ObjectMapperUtils.map(dto.getAddress(), Address.class);
        address = addressRepo.save(address);

        Company company = ObjectMapperUtils.map(dto, Company.class);
        company.setAddress(address);

        return ObjectMapperUtils.map(companyRepo.save(company), CompanyReadDto.class);
    }

    ...

}

EDIT:

CompanyReadDto:

@Getter
@Setter
public class CompanyReadDto {

    @Id
    @NotNull
    private Long id;

    @NotNull
    private String name;

    @NotNull
    private AddressReadDto address;

}

AddressReadDto:

@Getter
@Setter
public class AddressReadDto {

    @Id
    @NotNull
    private Long id;

    @NotNull
    private String address1;

    private String address2;

    @NotNull
    private String city;

    @NotNull
    private String state;

    @NotNull
    private int zipCode;

}
\$\endgroup\$
4
  • 1
    \$\begingroup\$ Shouldnt there be AddressReadDto and AddressService classes and CompanyServiceImpl would depend on address service rather then the repo directly? Now it seems that CompanyReadDto contains address entity and not dto, because there is no such dto. You might want to include CompanyReadDto definition in your question... \$\endgroup\$
    – slepic
    Apr 20 '20 at 7:29
  • \$\begingroup\$ @slepic thank you for your comment. I apologize I didn't include those files. Let me go ahead and edit those into the question. Also, what you're saying is that services should interact with eachother, as opposed to interacting with a repository that doesn't belong to that "entity"? \$\endgroup\$ Apr 20 '20 at 7:35
  • \$\begingroup\$ Either is fine, IMO. But the latter only as long as you dont interact with addresses from another entity's service. When you do, the address mapping code will repeat in this company service and the new service. If you separate it right Away you obey SRP And you won't have to touch the company service when new service needs addresses as well. What i find unclear Is what is returned by save methods of those two repos, do they return entity or dto? Or Is the transition from address entity to dto done by the utils mapper magically? Sry idk Java nor spring, would be probably Clear if i did :) \$\endgroup\$
    – slepic
    Apr 20 '20 at 7:57
  • \$\begingroup\$ @slepic No worries. So the repositories themselves return entity objects, so Address and Company. What the ObjectMapperUtils does is simply use modelmapper.org to map the entities to dtos, then the controller returns said dto. \$\endgroup\$ Apr 20 '20 at 17:57
2
\$\begingroup\$

Best practice to perform CRUD operations is to have this flow for an entity-

View --passing Dto--> Controller -- passing Dto/Entity--> Service --passing Entity--> Repo

In your example you can have both repositories inside a service as both entities ( company and address ) are associated.

Also, to fall in line you can save address entity along with country entity using cascade

\$\endgroup\$
2
  • \$\begingroup\$ Thank you! I went ahead and added cascading to my Company entity and I am able to save Company and Address without having to use address repository directly. This also deletes the address when a company is deleted (not that I will be deleting companies, but knowing that it works is good.) \$\endgroup\$ Apr 20 '20 at 18:00
  • \$\begingroup\$ Glad to know it helped :) \$\endgroup\$ Apr 20 '20 at 23:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.