As the documentation regarding these topics seems to be limited (and I was searching a lot - either wrong or the documentation is really limited), I would like to place the question here.
So far I could only find documentation that shows how to implement the basic CRUD operations (insert, delete, update, deleteAll, getAll) in the Android Architecture Components, but never queries which only return a single item. In general, the question is: Is the idea to hold all information in the repository by holding LiveData of all table contents and returning single objects from the repository?
Let me precise the question in two cases:
One table / entity
Two tables / entities with a 1:many relationship
One table
I fully get the concept of using LiveData for a single table, which I can use in a recycler view to list all table rows. But in many cases, I only need one row/object to work with. For example when editing one item.
Question 1: Is it common to implement a method on the repository to get the needed item out of the LiveData<List> allObjects like below? Of course, I could also pass all information from the last activity to my editActivity through my intent, but I find it easier to implement if I just pass the ID of an object and load it in my editActivity.
private LiveData<List<object>> allObjects;
public void getObjectById(int id){
for (Object o : allObjects) {
if(o.getid() == id){
return o;
}
}
Two tables
I also get the idea of having two entities and defining their relation in a separate class. Let's use a common example from the documentation: school with students (1:m).
Question 2: Is it common to hold LiveData<List> in my repository?
In my recycler view, I could use this list to display (for example) all schools with their number of students. Therefore I might not need the LiveData allSchools anymore.
Question 3: What is the best way to implement a query which returns me a student and the school he is visiting? I could implement a (relationship) class StudentWithSchool and keep LiveData of it in my repository.
private LiveData<List<StudentWithSchool>> allStudentsWithSchool;
public void getStudentWithSchoolByStudentId(int id){
for (StudentWithSchool s : allStudentsWithSchool) {
if(s.getid() == id){
return s;
}
}
It would be really helpful if somebody can explain to me how to implement the above examples correctly. Thank you, guys!
Related
I'm sure there is an answer to this already, I just don't know how to describe what I need to do in good search terms.
Let's say I am trying to make a program that handles the sale of unique pieces of wood (each has an ID) as well as tables made of those unique pieces of wood. I have two classes: WoodPiece and Table.
How should I create the Table class so that it can have instances of Table with unique wood pieces listed out so that you can add and remove the pieces up until the point the table is actually made and sold? Right now I'm thinking I make Table a subclass WoodPiece and it just has an ArrayList of woodPieces.
I'm not great at Java so I want to make sure I have the right idea before I waste a bunch of hours going backwards. Any tutorials you know of about this would be great. I'm using JavaFx for my program.
I would construct the Table class using composition. A Table is not a WoodPiece, but rather it contains WoodPieces. In the future, a Table may have a tablecloth or people, etc.
class Table
{
private Map<String, WoodPiece> woodPieces = new HashMap<>();
public Table ()
{
// constructor
}
public void addWoodPiece (WoodPiece wp)
{
woodPieces.put(wp.getID(), wp);
}
public WoodPiece removeWoodPiece (String id)
{
return woodPieces.remove(id);
}
}
Note: I went with a map instead of a List since your WoodPiece object has a unique ID associated with it. Furthermore, I assume you don't care about the order of the woodPieces since a Table really doesn't have a natural ordering of the wood that composes it.
Further reading: https://en.wikipedia.org/wiki/Composition_over_inheritance
I understand with your description that I table is only made with unique pieces and is not possible to made a table with other tables. So you only have to add a List of WoodPiece to your table class and the add and remove methods.
In case you want to be able to make a table with other tables you should first create an interface (let's call it TablePiece) and both Table and WoodPiece must implement it and Table must have a List of TablePiece. In the following graph Component would be TablePiece, Leaf WoodPiece and Composite Table.
Let's say I have a class Item. Items have object attributes and collection of other objects attributes:
public class Item
{
//Object attributes
String name;
int id;
Color color;
//Collection of object attributes
List<Parts> parts;
Map<int,Owner> ownersById;
}
I have a fairly simple web application that allows crud operations on these items. This is split up into separate operations:
a page where you can update the simple object attributes (name, id...).
a page where you can edit the collection of parts.
a page where you can edit the map of owners.
Because the server load was getting too high, I implemented a cache in the application which holds the "most recently used item objects" with their simple attributes and their collection attributes.
Whenever an edit is made to the name of an item, I want to do the following do things:
Persist the change to the item's name. This is done by converting the item object to xml (without any collection attributes) and calling a web service named "updateItemData".
Update the current user's cache by updating the relevant item's nme inside the cache. This way the cache stays relevant without having to load the item again after persisting it.
To do this I created the following method:
public void updateItem(Item itemWithoutCollectionData)
{
WebServiceInvoker.updateItemService(itemWithoutCollectionData)
Item cachedItemWithCollectionData = cache.getItemById(itemWithoutCollectionData.getId());
cachedItemWithCollectionData.setName(itemWithoutCollectionData.getName());
cachedItemWithCollectionData.setColor(itemWithoutCollectionData.getColor());
}
This method is very annoying because I have to copy the attributes one by one, because I cannot know beforehand which ones the user just updated. Bugs arised because the objects changed in one place but not in this piece of code. I can also not just do the following: cachedItem = itemWithoutCollectionData; because this would make me lose the collection information which is not present in the itemWithoutCollectionData variable.
Is there way to either:
Perhaps by reflection, to iterate over all the non-collection attributes in a class and thus write the code in a way that it does not matter if future fields are added or removed in the Item class
Find a way so that, if my Item class gains a new attribute, a warning is shown in the class that deals with the caching to signal "hey, you need to update me too!")?
an alternative which might seem a bit overkill: wrap all the non-collection attributes in a class, for example ItemSimpleData and use that object instead of separate attributes. However, this doesn't work well with inheritance. How would you implement this method in the following structure?
classes:
public class BaseItem
{
String name;
int id;
}
public class ColoredItem
{
Color color;
}
There many things that can be done to enhance what you currently have but I am going to point out just two things that may help you with your problem.
Firstly, I am assuming that public void updateItem is a simplified version from your production code. So; make sure this method is thread safe, since it is a common source or problems when it comes to caching.
Secondly, you mentioned that
Perhaps by reflection, to iterate over all the non-collection
attributes in a class and thus write the code in a way that it does
not matter if future fields are added or removed in the Item class.
If I understand the problem correctly; then, you can easily achieve this using BeanUtils.copyProperties() here is an example:
http://www.mkyong.com/java/how-to-use-reflection-to-copy-properties-from-pojo-to-other-java-beans/
I hope it helps.
Cheers,
The project has 4 classes. A Person, an Employee that extends Person and an Academic that extends Employee.
I also have a Store, which is a user-made alternative to an Array. One of the functions of Store is ‘elementAt()’, which returns to us an object in Store.
The problem I have is that elementAt() always returns as type Person. This is a huge problem because, in my Controller class, before I let the user perform an action only applicable to an Academic I NEED to check whether the user has actually chosen an employee or not.
public Person elementAt(int index)
{
// Returns element at position index
return list[index];
}
There is one big problem; according to the project specification I cannot alter the Person, Employee, Academic or Store class any further. Meaning, I have to determine the type of the Store index somewhere, somehow within my controller class.
I wanted to run this by people with more experience so thank you for having a look.
Instanceof seems to me the only option you have; and I don't think that its evil to use it in this case. But you are right, it is not the nicest thing in thinking in objects ;o)
At least you might encapsulate that like
public boolean isAcademic(Person p) {
return p instanceof Academic;
}
to concentrate the "code smell" in one position, and make it easier to later refactor it.
I don't know if i got it right, but if you just want to check the returned object type, do this:
Person person = store.elementAt(0);
if (person instanceof Academic) {
//do stuff
}
A controller in my spring mvc app is giving an empty concepts collection for a DrugWord entity when there are DrugConcepts in the database for every DrugWord. How can I change my code so that it populates the concepts collection with the appropriate number of DrugConcept instances for each DrugWord instance?
Here is the JPA code that queries the database:
#SuppressWarnings("unchecked")
public DrugWord findDrugWord(String wrd) {
System.out.println("..... wrd is: "+wrd);
return (DrugWord) em.find(DrugWord.class, wrd);
}
Here is the code for the relevant controller method, which prints out 0 for the size of sel_word.getConcepts().size() when the size should be at least 1:
#RequestMapping(value = "/medications", method = RequestMethod.GET)
public String processFindForm(#RequestParam(value="wordId", required=false) String word, Patient patient, BindingResult result, Map<String, Object> model) {
Collection<DrugWord> results = this.clinicService.findDrugWordByName("");
System.out.println("........... word is: "+word);
if(word==null){word="abacavir";}
model.put("words", results);
DrugWord sel_word = this.clinicService.findDrugWord(word);
System.out.println(";;;; sel_word.concepts.size(), sel_word.getName() are: "+sel_word.getConcepts().size()+", "+sel_word.getName());
model.put("sel_word", sel_word);
return "medications/medsList";
}
Is the problem that I only have GET programmed? Would the problem be solved if I had a PUT method? If so, what would the PUT method need to look like?
NOTE: To keep this posting brief, I have uploaded some relevant code to a file sharing site. You can view the code by clicking on the following links:
The code for the DrugWord entity is at this link.
The code for the DrugConcept entity is at this link.
The code for the DrugAtom entity is at this link.
The code to create the underlying data tables in MySQL is at this link.
The code to populate the underlying data tables is at this link.
The data for one of the tables is at this link.
Some representative data from a second table is at this link.(This is just 10,000 records from the table, which has perhaps 100,000 rows.)
The data for the third table is at this link. (This is a big file, may take a few moments to load.)
The persistence xml file can be read at this link.
To help people visualize the underlying data, I am including a print screen of the top 2 results of queries showing data in the underlying tables as follows:
The problem seemed to be that the DB was corrupt, specifically that you had new lines characters in every word, so that the queries always returned an empty result. Besides there were some problems that very big graphs of entities were loaded from DB, triggering a lot of SQL queries.
First of all you can change the findDrugWord method to be like:
public DrugWord findDrugWord(String wrd) {
em.find(DrugWord.class, wrd);
}
Because word is the PK and you've already set fetching when you put #ManyToMany there. I can imagine that the duplicate fetch definition confuses your JPA provider, but it won't help it that's for sure. :)
Secondly, take a look at this line:
PropertyComparator.sort(sortedConcepts, new MutableSortDefinition("concept", true, true));
I can't see concept attribute in your DrugConcept entity. Didn't you want to write rxcui?
But if you really want to have it sorted every time, add #OrderBy("rxcui ASC").
I wouldn't make any sort in place of an Entity's Collection. Especially without properly overridden hashCode and equals: You can't be sure how Spring sorts your Collection with reflection in the background which can lead to lot of headaches.
Hope this helps ;)
In the model layer of an application I'm working on, I have an Organization class, that has a one-to-many relationship with a Person class. Person objects can have a number of different roles, based on their one-to-many relationships to another set of objects of the superclass Certificate. To determine if a Person is a "signatory", I call
public boolean isSignatory() {
return this.certificatesAsSignatory.size() > 0;
}
I want to return a list of signatories for an organization, so I'm going to loop through the set of related persons, checking for signatories. What I'd like to do is cache the result, so I don't have to regenerate the data from the database each time. I've added a private field to Organization that looks like
private List<Person> signatories;
and the basic method looks like this
public List<Person> getSignatories() {
for ( final Person person : this.people ) {
if ( person.isSignatory() ) {
this.signatories.add( person );
}
}
return this.signatories;
}
Now, when I call the method to return the list, I'll store the result in signatories and return it. When it's called again, I can check if signatories already contains a list, and return that instead of doing the calculations again.
My question is this: how do I keep the cache of the list of signatories up to date?
So the list contains all persons who are signatories. It would seem a good idea to update that list every time Person changes from being a signatory to not being one, or vice versa. Im guessing you have some method that sets if a Person is a signatory or not? In that function you could make a call to clear the cache so it would refill the list next time it is needed. Im also guessing it can be done when a new Person is inserted into the db and should be a signatory.
Its hard to be more specific since I dont know how your code is sturctured. But the idea of a cache is to reset it when the data thats in it changes.