In a Spring Boot app, I have the following entities that have one-to-many relationship (Category is the parent of Recipe):
@Entity
public class Recipe {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 50)
private String title;
@ManyToOne(optional = true, fetch = FetchType.LAZY)
@JoinColumn(name = "category_id", referencedColumnName = "id")
private Category category;
}
@Entity
public class Category {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true, nullable = false, length = 50)
private String name;
@OneToMany(mappedBy = "category", cascade = CascadeType.ALL)
private Set<Recipe> recipes = new HashSet<>();
public void addRecipe(Recipe recipe) {
recipes.add(recipe);
recipe.setCategory(this);
}
public void removeRecipe(Recipe recipe) {
recipes.remove(recipe);
recipe.setCategory(null);
}
}
When I create a Recipe, I send categoryId
that is selected from Dropdown list and create Recipe by retrieving and adding category to the recipe as shown below:
@Transactional
public void update(RecipeRequest request) {
final Category category = categoryRepository.findById(request.getCategoryId())
.orElseThrow(() -> new NoSuchElementFoundException(NOT_FOUND_CATEGORY));
/* instead of retrieving category, I want to set the categoryId field of Recipe,
but there is not such kind of setter */
recipe.setCategoryId(request.getCategoryId());
recipe.setTitle(capitalizeFully(request.getTitle()));
recipe.setCategory(category);
recipeRepository.save(recipe);
}
Instead of retrieving category, I want to set the categoryId field of Recipe, but there is not such kind of setter:
recipe.setCategoryId(request.getCategoryId());
So, what is the most proper way for just setting the categoryId of the recipe and then saving it without requiring the category from db? Do I need a setter for categoryId field to the Recipe (I thought it, but does not seem elegant way)?
CodePudding user response:
If your repository implements org.springframework.data.jpa.repository.JpaRepository
you may take advantage of using JpaRepository#getReferenceById
method, in that case Hibernate instead of querying DB for data will return proxy object. However, such implementation may cause issues in some cases, for example:
// this call typically returns entity
// or null if entity wasn't found
repository.findById(id);
but:
// this call returns proxy object
repository.getReferenceById(id);
// now instead of returning entity
// repository either returns initialized proxy
// object or throws EntityNotFoundException
// if entity wasn't found
repository.findById(id);
CodePudding user response:
I would just add a categoryId field along with the corresponding getter and settter methods to the Recipe class.
@Entity
public class Recipe {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 50)
private String title;
@ManyToOne(optional = true, fetch = FetchType.LAZY)
@JoinColumn(name = "category_id", referencedColumnName = "id")
private Category category;
@Column(name = "category_id", nullable = false)
private Integer categoryId;
// getters/setters
}
Having a categoryId field means that when we don't have to create an instance of Category when adding new Recipes. Sure, Recipe.category will be null but that's ok if we're just adding new Recipes. This approach could also prove beneficial if we later decide that we need to add many Recipes simultaneously.