Array in Android Room Relation - android-room

I have a class for Room relations:
data class PersonWithRelations(
#Embedded val person: Person,
#Relation(
parentColumn = "country_id",
entityColumn = "country_id",
) val country: Country?,
#Relation(
entity = EmergencyContact::class,
parentColumn = "person_id",
entityColumn = "person_id",
) val emergencyContacts: Array<EmergencyContactPerson>?,
// More relations here...
)
EmergencyContactPerson is another class helper for relation:
data class EmergencyContactPerson (
#Embedded val emergencyContact: EmergencyContact,
#Relation(
entity = Person::class,
parentColumn = "ec_person_id",
entityColumn = "person_id",
projection = ["person_id", "party_id", "first_name", "last_name"]
) val person: PersonWithRelations,
)
But I've the following error:
.../PersonWithRelations.java:18: error: Entity type in a Relation must be a class or an interface.
private final com.data.model.relations.EmergencyContactPerson[] emergencyContacts = null;
Everything works except when I add the Array<T> type. How to have an array of these Room relation helper classes inside another relation helper class?
This one of the classes with I'm strugglin with. Additionally, I've the following classes presenting the same problem (How to have array of relation helper classes?):
data class PartyWithRelations(
#Embedded val party: Party,
#Relation(
parentColumn = "party_id",
entityColumn = "party_id",
) val emailAddresses: Array<Email>?,
#Relation(
entity = Phone::class,
parentColumn = "party_id",
entityColumn = "party_id",
) val phoneNumbers: Array<PhoneWithRelations>?,
#Relation(
entity = PostalAddress::class,
parentColumn = "party_id",
entityColumn = "party_id",
) val postalAddresses: Array<PostalAddressWithRelations>?,
)
PhoneWithRelations and PostalAddressWithRelations are as follows:
data class PhoneWithRelations (
#Embedded val phone: Phone,
#Relation(
parentColumn = "phone_type_id",
entityColumn = "phone_type_id",
) val type: PhoneType?,
)
data class PostalAddressWithRelations(
#Embedded val postalAddress: PostalAddress,
#Relation(
parentColumn = "county_id",
entityColumn = "county_id",
) val county: County,
#Relation(
parentColumn = "geopoint_id",
entityColumn = "geopoint_id",
) val geopoint: Geopoint,
#Relation(
parentColumn = "default_geopoint_id",
entityColumn = "geopoint_id",
) val defaultGeopoint: Geopoint,
)
If I remove the Array type from all of theses relations, they do work, but I'm needing to return an Array of those types. For further information, those classes should look like the following JSON (Not intended to be a JSON/String type of return, the following JSON is just for having a picture):
"party": {
"partyId": 76730,
"emailAddresses": [],
"phoneNumbers": [
{
"phoneNumberId": 73376,
"areaCode": "111",
"phoneNumber": "5554433",
"type": {
"phoneNumberTypeId": 61,
"displayText": "Cell",
"sortOrder": 2
},
"priority": 1
}
],
"postalAddresses": [
{
"postalAddressId": 47857,
"street1": "STREET1",
"street2": "STREET2",
"city": "Lafayette",
"stateCode": "IN",
"zipCode": "CODE",
"county": {
"countyId": 3114,
"name": "Tippecanoe",
"isIndependentCity": false,
"stateCode": "IN"
},
"geopoint": {
"geopointId": 41278,
"lat": "LAT",
"lng": "LNG"
},
"defaultGeopoint": {
"geopointId": 41278,
"lat": "LAT",
"lng": "LNG"
}
}
]
},
Also, EmergencyContactPerson should look like this:
"person": {
"personId": 68206,
"firstName": "First Name",
"middleName": "",
"lastName": "Last Name",
"country": {
"countryId": 981,
"displayText": "United States"
},
"emergencyContacts": [
{
"emergencyContactId": 22949,
"person": {
"personId": 68207,
"party": {
"partyId": 76731,
"emailAddresses": [],
"phoneNumbers": [],
"postalAddresses": []
},
"firstName": "First Name",
"lastName": "Last Name"
},
"priority": 1,
"relationship": "Daughter",
"notes": "Primary Contact",
"showOnRouteSheets": false
},
],
},

Related

Nested serializer does not inherit overridden to_representation

I want to customise the output of serializer to group some fields of the models into a nested dictionary, so I override to_representation:
My models.py
class Snippet(models.Model):
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=True, default='')
code = models.TextField()
linenos = models.BooleanField(default=False)
language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)
style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)
owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)
class Meta:
ordering = ['created']
My serializers.py
class SnippetSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
class Meta:
model = Snippet
fields = ['id', 'title', 'code', 'linenos', 'language', 'style', 'owner']
def to_representation(self, instance):
return {
'id': instance.id,
'owner': instance.owner.username,
'therest': {
'title': instance.title,
'code': instance.code,
'linenos': instance.linenos,
'language': instance.language,
'style': instance.style
}
}
class UserSerializer(serializers.ModelSerializer):
snippets = SnippetSerializer
class Meta:
model = User
fields = ['id', 'username', 'snippets']
depth = 1
My expected outcome of users serializer is:
[
{
"id": 1,
"username": "admin",
"snippets": [
{
"id": 1,
"owner": "admin",
"therest": {
"title": "",
"code": "foo=\"bar\"\\n",
"linenos": false,
"language": "python",
"style": "abap"
}
}
]
}
]
but I got this instead:
[
{
"id": 1,
"username": "admin",
"snippets": [
{
"id": 1,
"created": "2022-09-01T17:11:59.743112Z",
"title": "",
"code": "foo=\"bar\"\\n",
"linenos": false,
"language": "python",
"style": "abap",
"owner": 1
},
]
}
]
Nested snippets in UserSerializer does not inherit to_representation from SnippetSerializer. Did I miss something?

How to get consolidated Data in many to many with extra entity approach

Below are the Entities I have created to achieve Many to Many with an extra entity concept.
Company :
#Getter
#Setter
#Entity
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "companyId")
public class Company {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long companyId;
private String companyName;
#OneToMany(mappedBy = "company", fetch = FetchType.EAGER)
Set<CompanyUserMapping> companyUsers;
}
User :
#Getter
#Setter
#Entity
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "userId")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long userId;
private String email;
private String originalCompanyName;
#OneToMany(mappedBy = "user", fetch = FetchType.EAGER)
Set<CompanyUserMapping> companyUserMapping;
}
CompanyUserMapping
#Getter
#Setter
#Entity
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class CompanyUserMapping {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "company_id")
private Company company;
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "user_id")
private User user;
private boolean isExternal;
private boolean isActive;
}
Below is the way I am adding company with the user.
{
"company": {
"companyName": "XYZ company"
},
"user": {
"email": "sehwag#gmail.com",
"originalCompanyName": "XYZ company"
},
"active": true,
"external": false
}
And also trying to add the user to the existing company using below snippet.
Optional<User> optionalUser=userRepository.findByEmail(user.getEmail());
Optional<Company> optionalCompany = companyRepository.findById(companyId);
if(optionalUser.isPresent()) {
User existingUser=optionalUser.get();
Optional<CompanyUserMapping> optionalCompanyUserMapping=companyUserMappingRepository.findByCompanyAndUser(optionalCompany.get(),existingUser);
if(optionalCompanyUserMapping.isPresent()) {
throw new UserExistsForCompanyException("User exists for this company "+companyId);
}
CompanyUserMapping companyUserMapping =new CompanyUserMapping();
companyUserMapping.setCompany(optionalCompany.get());
companyUserMapping.setUser(existingUser);
companyUserMapping.setActive(true);
companyUserMapping.setExternal(false);
CompanyUserMapping savedcompanyUserMapping = companyUserMappingRepository.save(companyUserMapping);
return new ResponseEntity<CompanyUserMapping>(savedcompanyUserMapping, HttpStatus.CREATED);
}
CompanyUserMapping companyUserMapping =new CompanyUserMapping();
companyUserMapping.setCompany(optionalCompany.get());
companyUserMapping.setUser(user);
companyUserMapping.setActive(true);
companyUserMapping.setExternal(false);
CompanyUserMapping savedcompanyUserMapping = companyUserMappingRepository.save(companyUserMapping);
Here If I try to get Company details by Id, there is repeated information and also unwanted company information which is associated to few common users.The output Json is as below
{
"companyId": 1,
"companyName": "ABC company",
"companyUsers": [
{
"companyUserMappingId": 1,
"company": 1,
"user": {
"userId": 1,
"email": "sachintendulkar#gmail.com",
"companyUserMapping": [
1
]
},
"active": true,
"external": false
},
{
"companyUserMappingId": 3,
"company": 1,
"user": {
"userId": 3,
"email": "shanewarne#gmail.com",
"companyUserMapping": [
3,
{
"companyUserMappingId": 4,
"company": {
"companyId": 2,
"companyName": "XYZ company",
"companyUsers": [
{
"companyUserMappingId": 2,
"company": 2,
"user": {
"userId": 2,
"email": "sehwag#gmail.com",
"companyUserMapping": [
2
]
},
"active": true,
"external": false
},
4
]
},
"user": 3,
"active": true,
"external": false
}
]
},
"active": true,
"external": false
}
]
}
How do I get the consolidated data like below.
{
"companyId": 1,
"companyName": "ABC company",
"companyUsers": [
{
"companyUserMappingId": 1,
"user": {
"userId": 1,
"email": "sachintendulkar#gmail.com"
},
"active": true,
"external": false
},
{
"companyUserMappingId": 3,
"user": {
"userId": 3,
"email": "shanewarne#gmail.com"
},
"active": true,
"external": false
}
]
}
And then if I call get User by UserId, the consolidated data should be like below.
{
"userId": 1,
"email": "sachintendulkar#gmail.com",
"associatedCompany": [
{
"companyId": 1,
"companyName": "ABC company"
}
]
}

how to retrofit and room handle nested object

"provinsi": [
{
"createdDate": 1490089930310,
"createdBy": "SYSTEM",
"updatedDate": 1490089930310,
"updatedBy": "SYSTEM",
"id": 31,
"provinceName": "Kepulauan Riau",
"provinceCode": "0",
"mCities": [
{
"createdDate": 1490092020000,
"createdBy": "SYSTEM",
"updatedDate": 1490092020000,
"updatedBy": "SYSTEM",
"provinceName": "Kepulauan Riau",
"id": 198,
"cityName": "KAB.BINTAN",
"cityCode": "2102",
"centralBankCode": ""
},
{
"createdDate": 1490092020000,
"createdBy": "SYSTEM",
"updatedDate": 1490092020000,
"updatedBy": "SYSTEM",
"provinceName": "Kepulauan Riau",
"id": 350,
"cityName": "KAB.KARIMUN",
"cityCode": "2101",
"centralBankCode": "3801"
},
}
]
I tried to make it a relation table, or two tables. find good documentation for this but it's hard hahaha but can't find something like this
I think this will be a one-to-many relation. For example
Entity
#Entity
data class Dog(
#PrimaryKey val dogId: Long,
val dogOwnerId: Long,
val name: String,
val cuteness: Int,
val barkVolume: Int,
val breed: String
)
#Entity
data class Owner(#PrimaryKey val ownerId: Long, val name: String)
data class OwnerWithDogs(
val owner: Owner,
val dogs: List<Dog>
)
data class OwnerWithDogs(
#Embedded val owner: Owner,
#Relation(
parentColumn = "ownerId",
entityColumn = "dogOwnerId"
)
val dogs: List<Dog>
)
Dao
#Transaction
#Query("SELECT * FROM Owner")
fun getDogsAndOwners(): List<OwnerWithDogs>
You can see a good article at here.
I hope this will be helpful.

SlugField in ViewSet doesn't populare dropdown in JSON webform

I have a Django REST framework application with a course and department model. I have the following models, serializers and viewset to represent the course catalog.
## MODELS ##
class Department(models.Model):
"""Academic Department"""
name = models.CharField(max_length=30, unique=True)
class Course(models.Model):
"""Courses in the course catalog"""
course_name = models.CharField(max_length=30, unique=True)
department = models.ForeignKey(Department, on_delete=models.PROTECT)
course_number = models.DecimalField(decimal_places=0, max_digits=3, unique=True)
credits = models.IntegerField()
class Meta:
unique_together = (("department", "course_number"),)
## SERIALIZERS ##
class DepartmentSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = models.Department
#fields = ('id', 'last_name', 'first_name')
class CourseSerializer(serializers.ModelSerializer):
department = serializers.SlugRelatedField(
many = False,
read_only = False,
slug_field = 'name',
queryset = models.Department.objects.all()
)
class Meta:
model = models.Course
fields = (
'id',
'course_name',
'department',
'course_number',
'credits')
## VIEWSETS ##
class CourseViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows courses to be viewed or edited.
"""
queryset = models.Course.objects.all().order_by('department__name','course_number')
serializer_class = serializers.CourseSerializer
Course has a foreign key pointing to department and using the SlugRelatedField a courses department is listed in the result JSON as the department name:
{
"count": 5,
"next": null,
"previous": null,
"results": [
{
"id": 5,
"course_name": "History of Justin",
"department": "English",
"course_number": "344",
"credits": 3
},
{
"id": 6,
"course_name": "34",
"department": "Math",
"course_number": "4",
"credits": 4
},
{
"id": 1,
"course_name": "Pre Calc",
"department": "Math",
"course_number": "101",
"credits": 3
},
{
"id": 2,
"course_name": "Calc I",
"department": "Math",
"course_number": "200",
"credits": 3
},
{
"id": 3,
"course_name": "Calc II",
"department": "Math",
"course_number": "201",
"credits": 3
}
]
}
I can also populate new courses with the following body in a POST request:
{
"course_name": "Chemistry I",
"department": "Science",
"course_number": "200",
"credits": 3
}
However, the auto generated form does not render the slug field text.
.
How can I change what this form renders?
You'll need to add a __str__ method to Department in order to tell Django about how to represent a Department instance:
class Department(models.Model):
"""Academic Department"""
name = models.CharField(max_length=30, unique=True)
def __str__(self):
return self.name

Spring Data Rest output join column object as JSON field when querying single resource

I have Apartment entity:
#Entity
public class Apartment extends AbstractEntity {
private String name;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(nullable = false)
#RestResource(exported = false)
private Address address;
private String website;
#OneToMany(mappedBy = "apartment")
#RestResource(exported = false)
private Set<FloorPlan> floorPlans;
...
FloorPlan entity:
#Entity
public class FloorPlan extends AbstractEntity {
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "apt_id", nullable = false)
private Apartment apartment;
private float bed;
private float bath;
private int priceFrom;
...
I applied excerptProjection to Floorplan to only show bed, bath and priceFrom. When I query apartments collection, the json output looks ok:
{
"_embedded": {
"apartments": [
{
"name": "Avalon Silicon Valley",
"website": "https://www.avaloncommunities.com/california/sunnyvale-apartments/avalon-silicon-valley",
"address": {
"streetNumber": "1257",
"street": "Lakeside Drive",
"city": "Sunnyvale",
"state": "CA",
"zipCode": "94085",
"fullAddress": "1257 Lakeside Drive, Sunnyvale, CA 94085"
},
"floorPlans": [
{
"bed": 3,
"bath": 3,
"priceFrom": 4495
},
{
"bed": 3,
"bath": 2,
"priceFrom": 4760
},
However if I do a single resource like http://localhost:8080/ag-api/apartments/1
floorplans will output Apartment Object as one of its field:
{
"name": "Avalon Silicon Valley",
"address": {
"streetNumber": "1257",
"street": "Lakeside Drive",
"city": "Sunnyvale",
"state": "CA",
"zipCode": "94085",
"fullAddress": "1257 Lakeside Drive, Sunnyvale, CA 94085"
},
"website": "https://www.avaloncommunities.com/california/sunnyvale-apartments/avalon-silicon-valley",
"floorPlans": [
{
"bed": 3,
"bath": 3,
"priceFrom": 4495,
"_embedded": {
"apartment": {
"name": "Avalon Silicon Valley",
"website": "https://www.avaloncommunities.com/california/sunnyvale-apartments/avalon-silicon-valley",
"address": {
"streetNumber": "1257",
"street": "Lakeside Drive",
"city": "Sunnyvale",
"state": "CA",
"zipCode": "94085",
"fullAddress": "1257 Lakeside Drive, Sunnyvale, CA 94085"
},
"floorPlans": [
Anyone got an idea what might be going on? really appreciate it. Thanks
Not sure if it will help, but in documentation I found in order to omit "_embedded" in you response you'll need to add:
"spring.hateoas.use-hal-as-default-json-media-type=false" to application.properties.

Resources