I am new to Spring programming and trying the below example with one to many relationship between BID and BIDITEM classes. I am not sure whether the BIDITEM data is saved, as when I tried to retrieve the BID, I am getting only BID data and not BIDITEM data. Do we need to have a repository even for BIDITEM class. I can see that complete BID JSON string, along with BIDITEM is received in create method.
Could you please go through it, and let me know what is wrong with it.
#Entity
#Table(name = "bid")
public class Bid {
#Id
private String title;
#Column
private long startDate;
#Column
private long endDate;
#OneToMany(mappedBy = "myBid", cascade = {CascadeType.ALL})
private List<BidItem> bidItems = new ArrayList<BidItem>();
//Constructor, getter and setter methods go here
}
#Entity
#Table(name="biditem")
public class BidItem
{
#Id
private String item;
#Column
private String desc;
#Column
private double minAmt;
#ManyToOne
#JoinColumn(name = "title")
private Bid myBid;
//Constructor, getter and setter methods go here
}
public interface BidRepository extends CrudRepository<Bid, String> {
//Tried even JpaRepository
}
public class BidService {
ObjectMapper mapper = new ObjectMapper();
#Autowired
private BidRepository bidRepo;
public Bid create(String bidJson) throws JsonParseException, JsonMappingException, IOException
{
Bid bid = mapper.readValue(bidJson, Bid.class);
// bidJson string has below string
// {"bidItems":[{"item":"item1","desc":"item1","minAmt":"999"}],
// "title":"bid1","startDate":"D1","endDate":"D5"}
Bid savedBid = bidRepo.save(bid);
return savedBid;
}
public Bid findByID(String title)
{
Bid bid = bidRepo.findOne(title);
return bid;
}
}
Related
Here's nodeEntity
#Data
#NodeEntity
public class Resource {
#Id
#GeneratedValue
private Long id;
#Property("name")
private String name;
private String code;
#Property("parent_code")
private String parentCode;
private String label;
private Neo4jRelationship relationship;
}
And here's relationship between nodes
#Data
#RelationshipEntity
public class Neo4jRelationship {
#Id
private Long id;
#StartNode
private Resource startNode;
#EndNode
private Resource endNode;
}
I want to query all the relationship satify some condition,
#Query("match p = (a : category_first {name: $name})-[*1..2]-() return p")
List<Neo4jRelationship> getFistCatNode(#Param("name") String name);
but the query return am empty list.
However, if I change the return type to org.neo4j.ogm.model.Result, the query can return normally.
I'm confused why the first way dosen't work. Any help will be grateful
What is the standard object design for accepting a POST request from a client, saving the record to the database, and then returning a response back to the client? I'm working with the Spring framework.
Should I be sending back the entity and hiding properties that aren't necessary for the response?
#RestController
public class SomeController {
private final SomeService service;
#PostMapping(value = "/post/new", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<SomeEntity> post(#RequestBody final SomeEntity someEntity) {
SomeEntity savedEntity = service.save(someEntity);
return ResponseEntity.ok(savedEntity);
}
}
#Entity
#Table(name = "posts")
public class SomeEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "title")
private String title;
#Column(name = "body")
#JsonIgnore
private String body;
#JsonIgnore
#Column(name = "deleted_ind")
private boolean deleted;
#JsonIgnore
#Column(name = "author")
private String author;
#Column(name = "created_at")
private LocalDateTime createdAt;
}
or would I accept some sort of POST request object that I convert to an entity, then re-assemble the entity into a response?
#JsonIgnoreProperties(ignoreUnknown = true)
public class SomePostRequestResource {
private String title;
private String body;
private String createdAt;
}
#RequiredArgsConstructor
#RestController
public class SomeController {
private final SomeService service;
private final SomeResourceAssembler resourceAssembler;
#PostMapping(value = "/post/new", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<SomePostRequestResource> post(
#RequestBody final SomePostRequestResource someResource
) {
SomeEntity savedEntity = service.convertToEntityAndSave(someResource);
SomePostRequestResource response = resourceAssembler.toResource(savedEntity);
return ResponseEntity.ok(response);
}
}
But then maybe I only want to send back the createdAt, would I hide the other properties in the SomePostRequestResource, or do I need another object to represent the response, which only has the property I want to send back?
I would also appreciate any book or article suggestions related to desigining objects for use with a RESTful API. I have seen articles concerning how to design and name the endpoints, but not so many concerning how to design the objects on the backend.
I would recommend you create a DTO class for the incoming/outgoing data containing the filed that are set/viewable by the client like:
public class SomeEntityIncomingDto {
private String title;
....
}
public class SomeEntityOutgoingDto {
private Long id;
private String title;
....
}
On the other hand, You won't need to map your persistence entities to DTOs and vice versa manually, you can use a library like ModelMapper or MapStruct that handles the conversion automatically.
I'm having issues getting a neo4j RelationshipEntity persisted with Spring Boot. I'm using spring-boot-starter-data-neo4j (2.1.0.RELEASE), and the neo4j docker image tagged 3.4.9.
I have a simple NodeEntity, which contains a collection for the RelationshipEntity:
#NodeEntity
public class Book {
#Id
#GeneratedValue
private Long id;
private String name;
public Book() {}
public Book(String name) {
this.name = name;
}
#Relationship(type = "PURCHASED_WITH", direction = "OUTGOING")
private Set<BookPurchase> purchases = new HashSet<>();
// getters and setters follow
}
I have another NodeEntity, which also contains a collection for the relationship entity:
#NodeEntity
public class CreditCard {
#Id
#GeneratedValue
private Long id;
private String number;
#DateString(value = "yyyy-MM-dd")
private Date expiryDate;
public CreditCard() {}
public CreditCard(String number, Date expiryDate) {
this.number = number;
this.expiryDate = expiryDate;
}
#Relationship(type = "PURCHASED_WITH", direction = "INCOMING")
private Set<BookPurchase> purchases = new HashSet<BookPurchase>();
// getters and setters follow
}
I have the RelationshipEntity, which adds references to both NodeEntity classes in the constructor:
#RelationshipEntity(type = "PURCHASED_WITH")
public class BookPurchase {
#Id
#GeneratedValue
private long id;
#DateString("yyyy-MM-dd")
Date purchaseDate;
#StartNode
private Book book;
#EndNode
private CreditCard card;
public BookPurchase(){}
public BookPurchase(CreditCard card, Book book, Date purchaseDate) {
this.card = card;
this.book = book;
this.purchaseDate = purchaseDate;
this.card.getPurchases().add(this);
this.book.getPurchases().add(this);
}
// getters and setters follow
}
And finally I have the Spring controller tying everything together:
#RestController
public class ExamplesController {
#Autowired
CreditCardRepository creditCardRepository;
#PostMapping(value="/purchases")
public String createPurchases() {
CreditCard card = new CreditCard("11111", new GregorianCalendar(2018, Calendar.FEBRUARY, 12).getTime());
Book book1 = new Book("of mice and men");
BookPurchase purchase1 = new BookPurchase(card,book1,new GregorianCalendar(2018, Calendar.MARCH, 15).getTime());
creditCardRepository.save(card);
return "Successfully created entities";
}
}
Whenever I try to curl -X POST http://localhost:8080/purchases, I just see the following in the neo4j browser - the RelationshipEntity is not persisted, only the nodes.
Can anyone assist?
Thanks to Gerrit Meier for answering this one. My RelationshipEntity was using the primitive long instead of the object/wrapper Long. Complete details here: https://community.neo4j.com/t/neo4j-relationshipentity-not-persisted/3039
I am working on a spring boot application with Hibernate as ORM and Jackson as JSON serialiser .
I have three model objects and CRUD operations for all three models.
Class Student{
private Teacher teacher; // Teacher of the student — to be fetched eagerly
+Getter/Setter
}
class Teacher {
private List<Subject> subject; // List of subjects associated to that user— to be fetched eagerly
+Getter/Setter
}
class Subject {
private long subjectId
//Other subject properties
+ Getter/Setter
}
Whenever I trigger a get request for student info I get the teacher info which is correct where as I also receive Subject info as well which is unnecessary for me. In the same time when I request for Teacher info, I need Subject info should be associated to that for sure. If I use #JsonBackReference for subject I am losing it all the time. I am not sure how to achieve this.
Thanks in advance for your help!!
You can also annotate like this
Class Student{
#JsonIgnoreProperties("subject")
private Teacher teacher; // Teacher of the student — to be fetched eagerly
}
You can use JSON Views
From the spring blog:
public class View {
interface Summary {}
}
public class User {
#JsonView(View.Summary.class)
private Long id;
#JsonView(View.Summary.class)
private String firstname;
#JsonView(View.Summary.class)
private String lastname;
private String email;
private String address;
private String postalCode;
private String city;
private String country;
}
public class Message {
#JsonView(View.Summary.class)
private Long id;
#JsonView(View.Summary.class)
private LocalDate created;
#JsonView(View.Summary.class)
private String title;
#JsonView(View.Summary.class)
private User author;
private List<User> recipients;
private String body;
}
and in the controller
#RestController
public class MessageController {
#Autowired
private MessageService messageService;
#JsonView(View.Summary.class)
#RequestMapping("/")
public List<Message> getAllMessages() {
return messageService.getAll();
}
#RequestMapping("/{id}")
public Message getMessage(#PathVariable Long id) {
return messageService.get(id);
}
}
PS: No link to http://fasterxml.com/ as it's currently down.
Can you tell me, why the record is posted twice in the database. I think. this happens because I use save() method. But shouldn't I save the master-entity and dependent-entity separately?
Controller method:
#RequestMapping(value = "/addComment/{topicId}", method = RequestMethod.POST)
public String saveComment(#PathVariable int topicId, #ModelAttribute("newComment")Comment comment, BindingResult result, Model model){
Topic commentedTopic = topicService.findTopicByID(topicId);
commentedTopic.addComment(comment);
// TODO: Add a validator here
if (!comment.isValid() ){
return "//";
}
// Go to the "Show topic" page
commentService.saveComment(comment);
return "redirect:../details/" + topicService.saveTopic(commentedTopic);
}
Services:
#Service
#Transactional
public class CommentService {
#Autowired
private CommentRepository commentRepository;
public int saveComment(Comment comment){
return commentRepository.save(comment).getId();
}
}
#Service
#Transactional
public class TopicService {
#Autowired
private TopicRepository topicRepository;
public int saveTopic(Topic topic){
return topicRepository.save(topic).getId();
}
}
Model:
#Entity
#Table(name = "T_TOPIC")
public class Topic {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
#ManyToOne
#JoinColumn(name="USER_ID")
private User author;
#Enumerated(EnumType.STRING)
private Tag topicTag;
private String name;
private String text;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "topic", cascade = CascadeType.ALL)
private Collection<Comment> comments = new LinkedHashSet<Comment>();
}
#Entity
#Table(name = "T_COMMENT")
public class Comment
{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
#ManyToOne
#JoinColumn(name="TOPIC_ID")
private Topic topic;
#ManyToOne
#JoinColumn(name="USER_ID")
private User author;
private String text;
private Date creationDate;
}
In this concrete case, you do not need to save the master and the client.
Saving the master or the client would be enough (with this concrete mapping)
But I think the main problem is that you do not have a good equals method in your Comment so your ORM Provider think that there are two different comments, and therefore store them twice.