I have one to many relationship(Model 1->N Field), I want find all model with their fields. but the model's fields is empty object.
#NodeEntity
public class Model {
#Id
private String id;
private String name;
#Relationship(type = "ModelField", direction = Relationship.OUTGOING)
private List<Field> fields = new ArrayList<Field>();
}
#NodeEntity
public class Field {
#Id
private String id;
private String name;
}
public interface ModelRepo extends Neo4jRepository<Model, String>{
}
public ModelRepo mr;
Iterable<Model> models = mr.findALl();
// the model's fields is empty
I just reconstructed your scenario basing on your correct code and it works fine. I assume by populating your data something went wrong. Because that piece of code is missing, I can’t point you to the concrete reason. To help you nevertheless, I outline my steps to retrieve your field nodes.
Adding a FieldRepo repository:
public interface FieldRepo extends Neo4jRepository<Field, String> {
}
Populating your scenario:
Model model = new Model("modelId1", "Model1");
Field field = new Field("fieldId1", "Field1");
model.getFields().add(field);
Field field2 = new Field("fieldId2", "Field2");
model.getFields().add(field2);
modelRepo.save(model);
fieldRepo.save(field);
fieldRepo.save(field2);
Retrieving your information:
Iterable<Model> resultModels = modelRepo.findAll();
for (Model resultModel : resultModels) {
System.out.println("Model: " + resultModel.getId() + " " + resultModel.getName());
for (Field resultField : resultModel.getFields()) {
System.out.println("\tField: " + resultField.getId() + " " + resultField.getName());
}
}
Which results in the following, your expected output:
Model: modelId1 Model1
Field: fieldId1 Field1
Field: fieldId2 Field2
Result - graphical representation
I hope that this information proves helpful. Please don't hesitate to ask any unclear items.
Related
Let says I have a basic case where I map an object to an other, I need to declare the mapping in the Mapper class.
For validation I may want to remember the original field name and his corresponding mapping.
Is there a way to do it with mapstruct without having to do a mapping "manually"
here is an example of what I would expect.
public class PersonDemo {
public static void main(String[] args) {
final PersonMapper mapper = Mappers.getMapper(PersonMapper.class);
Person person = mapper
.toPerson(new PersonDto()
.setFirstName("John")
.setName("Doe"));
System.out.println(person);
System.out.println("Expected " + toPersonDesc("firstName") + " to be firstName");
System.out.println("Expected " + toPersonDesc("name") + " to be lastName");
}
#Mapper
public interface PersonMapper {
#Mapping(target = "lastName", source = "name")
Person toPerson(PersonDto dto);
}
//expected method. to be generated somehow from the mapping.
static String toPersonDesc(String fieldName) {
switch (fieldName) {
case "name": return "lastName";
case "firstName": return "firstName";
}
return null;
}
#Data
#Accessors(chain = true)
public static class Person {
private String lastName;
private String firstName;
}
#Data
#Accessors(chain = true)
public static class PersonDto {
private String name;
private String firstName;
}
}
It's impossible with Mapstruct. There's another question similar to yours: How to provide MapStruct Mapping annotation mapping meta data at runtime. The answer there describes "some" approach to the problem, but it's very limited - it simply scrapes the information from the #Mapping annotations (no support for implicit mappings).
It would be quite useful to have this though - you should propose this feature to the Mapstruct team.
I want to convert a string to json list. I am currently working on a web api using spring boot. There is a table which contains multiple value at a ssingle column and similarly all the columns are having multi values. Like: There is a car company. There is a column named models - which contains more than one models and then there there is a price column which contains all the models price respectively.
Now I have to convert those strings to json format.
I tried using the split() in java for that but that is giving the address location as output.
Model class
..........//getters and setters and declarations
#Override
public String toString() {
String ar = car_type;
String ar1[]=ar.split(",");
int l = ar1.length;
return "{" +
"\"car_comp\":" +"\"" + car_comp+ "\""+"," +
"\"car_type\":" +"\""+ ar1 + "\""+","+
"\"car_price\":" +"\""+ car_price+ "\""+","+
"\"car_comp_value\":"+"\"" + car_comp_value +"\""+
'}';
}
I used the length function to check whether the array is being created of the right size or not.
The Output
"car_comp": {
"car_comp": "bmw",
"car_type": "[Ljava.lang.String;#4017b770",
"car_price": "$1500",
"car_comp_value": "$65.4M"
}
PLEASE IGNORE THE DATA..
But the car type is showing not what I expected.
To be honest this is my first time working in web api and json and I don't have much idea how to do things with it.
The Expected Output :
"car_comp": {
"car_comp": "bmw",
"car_type": [{modelA},{modelB},{modelC}],
"hb_unit_hints": "Kg",
"hb_value": "65.4"
}
Thanks in Advance.
String ar = car_type;
String ar1[]=ar.split(",");
There, I feel your problem is trying to map a String column of a table entity to a List model field. If you had a car model with List field then model to JSON string conversion is straight-forward using jackson-objectmapper like:
Car model:
public class Car {
String car_comp;
List<String> car_type;
String car_price;
String car_comp_value;
}
Converting Car model object to JSON string:
ObjectMapper objectMapper = new ObjectMapper();
Car car = new Car();
car.car_comp = "BMW";
car.car_type = Arrays.asList("modelA", "modelB", "modelC");
car.car_price = "$1500";
car.car_comp_value = "$65.4M";
String json = objectMapper.writeValueAsString(car);
If you are using JPA Entity to map database tables to models, you can use javax.persistence.AttributeConverter to convert a comma-separated String column to a List field of the entity, like:
Custom attribute converter:
public class CarTypeConverter implements AttributeConverter<List<String>, String> {
#Override
public Long convertToDatabaseColumn(List<String> attribute) {
if (attribute == null) return null;
return attribute.stream().reduce((x, y) -> x + "," + y).orElse("");
}
#Override
public List<String> convertToEntityAttribute(String dbColumnValue) {
if (dbColumnValue == null) return null;
String[] typeArray = dbColumnValue.split(",");
List<String> typeList = Arrays.stream(typesArray).collect(Collectors.toList());
return typeList;
}
}
Car database entity:
#Entity
#Table(name = "car_comp")
class Car {
#Column(name = "car_comp")
String car_comp;
#Column(name = "car_type")
#Convert(converter = CarTypeConverter.class)
List<String> car_type;
#Column(name = "car_price")
String car_price;
#Column(name = "car_value")
String car_comp_value;
//getters and setter below...
}
Since you are using spring boot, You could implement that using ObjectMapper.
So I will just create model for clear explanation
Car Model
class Car {
#JsonProperty(value = "car_company")
private String carCompany;
#JsonProperty(value = "car_type")
private List<CarType> carType;
#JsonProperty(value = "car_price")
private String carPrice;
// Getter, Setter, All Args
}
Car Type
class CarType {
#JsonProperty(value = "type")
private String type;
//Getter, Setter, All Args
}
Implementation
ObjectMapper mapper = new ObjectMapper();
List<CarType> carTypes = Arrays.asList(new CarType("SEDAN"), new CarType("HATCHBACK"));
Car car = new Car("Telsa", carTypes, "1000");
System.out.println(mapper.writeValueAsString(car));
//Output :
//{"car_company":"Telsa","car_type":[{"type":"SEDAN"},{"type":"HATCHBACK"}],"car_proce":"1000"}
JsonNode jsonNode = mapper.valueToTree(car);
// It also gives you JsonNode
I have following method which works fine however returns the objects in the alphabetical orders whenever being called from calling method :-
public List<Object> getExportDataFromView() {
try {
String selectQuery = "SELECT UNIQUE_ID, DATE, CODE, PRODUCT_CODE, "
+ " MESSAGE AS MESSAGE_TEXT, SOURCE, COMPANY_ID, REMARK, BATCH, COUNTRY, PRODUCT_CODE_SCHEME, EXTERNAL_TRANSACTION_ID, RETURN_CODE, CORRELATION_ID, BUSINESS_PROCESS, BATCH_EXPIRY_DATE "
+ " FROM \"test\".\"my-systems.Company::views.Export_Data_View\" "
+ " WHERE COMPANY_ID = 'C100' "
+ " ORDER BY DATE DESC";
Query q = this.em.createNativeQuery(selectQuery, ExportData.class);
return q.getResultList();
} catch (Exception e) {
return null;
} finally {
this.em.close();
}
}
Whenever this method is called from another calling method, the List returned is in sorted order (alphabetically). However, in the JPA Entity class of ExportData.java, the fields are declared in original order like below :-
#Entity
#Table(name = "\"my-systems.Company::views.Export_Data_View\"", schema="\"test\"")
public class ExportData implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private String UNIQUE_ID;
private String CODE;
private String PRODUCT_CODE;
private String MESSAGE_TEXT;
private String SOURCE;
Is there any way to preserve the same order as declared in Entity class rather than being sorted without changing the return type i.e. List.
Any help would be highly appreciated.
Thank you
I am using Play framework with Ebean. I have two models, below are the code:
public class User extends Model {
#Id
public Long id;
public String name;
/* rest of attributes */
public static Finder<Long,User> find = new Finder<Long,User>(
Long.class, User.class
);
}
public class Admin extends Model {
#Id
public Long id;
#OneToOne
public User user;
/* rest of attributes */
public static Finder<Long,Admin> find = new Finder<Long,Admin>(
Long.class, Admin.class
);
}
When I do Logger.info(admin.user.name) in Java, I can see the name of the admin. But when I pass the Java object to Scala using view render, if I do #admin.user.id, I can still get the id, but if I do #admin.user.name, I get nothing (with no error). I'm just wonder how can I access the name attribute from a joined table?
Problem solved.
Before when I do the fetching, I did
Admin.find.where()
.ilike("user.name", "%" + filter + "%")
.orderBy("user."+sortBy + " " + order)
.findPagingList(pageSize)
.getPage(page);
After changing to
Admin.find.fetch("user", new FetchConfig().query())
.where()
.ilike("user.name", "%" + filter + "%")
.orderBy("user."+sortBy + " " + order)
.findPagingList(pageSize)
.getPage(page);
It successfully displayed instance variables on Scala.
I've done the following mapping:
#Entity
#Table(name = "NWS_NEWS")
public class News implements Serializable {
private static final long serialVersionUID = 5246618151933389186L;
private String id;
private List<Picture> pictures;
+ OTHER fields / getters / setters, no matter
#Id
#GeneratedValue(generator = "juuid")
#Column(length = 36)
public String getId() {
return id;
}
#CollectionOfElements
#JoinTable(name = "NWS_PICTURES",joinColumns = #JoinColumn(name="NEWS_ID"))
#CollectionId(
columns= #Column(name="PICTURE_ID"),
type=#Type(type="long"),
generator="sequence")
public List<Picture> getPictures() {
return pictures;
}
public void setPictures(List<Picture> pictures) {
this.pictures = pictures;
}
}
And my picture is:
#Embeddable
public class Picture implements Serializable {
private static final long serialVersionUID = -1397366206984323622L;
private News news;
private String path;
private ImageSize imageSize;
#Parent
public News getNews() {
return this.news;
}
#Column(name = "path", nullable=false)
public String getPath() {
return path;
}
#Enumerated(EnumType.STRING)
#Column(name = "size", nullable=false)
public ImageSize getImageSize() {
return imageSize;
}
public void setImageSize(ImageSize imageSize) {
this.imageSize = imageSize;
}
public void setNews(News news) {
this.news = news;
}
public void setPath(String path) {
this.path = path;
}
}
And my dao test is:
#Test
public void testAddPicturesToNews() {
News newsToSave = new News();
// Create big picture
Picture pBig = new Picture();
pBig.setImageSize(ImageSize.BIG);
pBig.setPath("/tmp/blabla_big.jpg");
// Create medium picture
Picture pMedium = new Picture();
pMedium.setImageSize(ImageSize.MEDIUM);
pMedium.setPath("/tmp/blabla_med.jpg");
// Set the pictures in the news
List<Picture> picturesList = new ArrayList<Picture>();
picturesList.add(pBig);
picturesList.add(pMedium);
newsToSave.setPictures(picturesList);
// Save the news
this.newsDAO.saveOrUpdate(newsToSave);
String newsId = newsToSave.getId();
News newsLoaded = this.newsDAO.findById(newsId);
List<Picture> picturesLoaded = newsLoaded.getPictures();
for ( Picture pictureLoaded : picturesLoaded ) {
System.out.println(pictureLoaded.getPath());
System.out.println(pictureLoaded.getImageSize());
System.out.println(pictureLoaded.getNews());
System.out.println("\n");
}
}
But the output is:
/tmp/blabla_big.jpg
BIG
null
/tmp/blabla_med.jpg
MEDIUM
null
Actually i don't understand why getNews() returns null in the child entity entity, while it has the "#Parent" annotation. Am i doing something wrong?
Anyway the concept of getting the parent in a child entity seems a bit strange for me since what would happen if i do something like that:
News news1 = new News();
News news2 = new News();
List<Picture> picList = new ArrayList<Picture>();
Picture picture1 = new Picture();
picturesList.add(picture1);
picture1.setNews(news2);
news1.setPictures(picList);
this.newsDAO.saveOrUpdate(news1);
this.newsDAO.saveOrUpdate(news2);
What would happen since the same picture will be in news1 list, but also its parent was set to news2???
I think i'll do without that parent, i don't need that so much but it's just curiosity...
Thanks
Btw i'd like to have only one picture of each size for a news -> there can't be 2 small pictures for the same news.
So is it possible to add a unique constraint on {news_id , imageSize} in my embedded entity? I don't see how to do that since no id field is declared in my Picture embeddable entity
I'm not familiar with the #Parent annotation for an #Embeddable, but for "real" relationships it's always recommended to do something like this:
// News class
public void setPictures(List<Picture> pictures) {
this.pictures = pictures;
for (Picture picture : pictures) {
picture.setNews(this);
}
}
public void addPicture(Picture picture) {
this.pictures.add(picture);
picture.setNews(this);
}
Remember that OOP, as opposed to the relational model, has only the notion of a "one-way" navigation, and that you should build the "two-way" by yourself. Encapsulating this behavior in the setter makes this transparent to your consumers. So, I'm not sure why your #Parent is not working, but I would try to do the opposite:
// what you have:
newsToSave.setPictures(picturesList);
// what I'd try:
pMedium.setNews(newsToSave);
What would happen since the same picture will be in news1 list, but also its parent was set to news2???
Well, an #Embeddable is an object which is "embedded" into another, meaning that it belongs only to that other object (parent). As such, it should contain only one parent. If you change the parent, it'll belong only to this new parent. If you need an object (Picture) to have a relationship with other objects (News), you'll need a #ManyToMany (if the other object, News, may also be linked to several Picture)