0 votes
asked in MicroStream for Java by (220 points)
My dataroot object consists of 3 lists (customers, products and vendors). Now, I need to add a new list (stock) to the dataroot object. It works when I start with an empty database, obviously, however, on the live database, the new list is never added.

What are the steps to add a new object to the dataroot ?

2 Answers

+2 votes
answered by (3.4k points)
selected by
 
Best answer

Hello,

There is one more important part beside the improvements from Fred:
The modified root element needs to be stored to updated it in the storage.
This could be done by a simple:

storageManager.store((DataRoot)storageManager.root());

after starting the storage.

 

The reason for this is:

After upgrading the DataRoot class the storage still has the old version persisted. During loading this old class is matched to the new version. Therefore, you can work with new field (List<Wheel> wheels) and see it if you debug your application.

But the new(updated) instance of the dataRoot needs to be stored again to apply the change to the storage.

 

Best regards

commented by (220 points)
Harald,

Spot on...! Thanks a lot !!

Maybe an enhancement request: when closing the database at exit time, microstream could warn that there were changes to the root that are not saved ?

Best regards,

Hans.
commented by (3.4k points)
Hello Hans

We discussed that issue today and we agreed that the current behavior could be improved. So many thanks for your Question.

best regards
+1 vote
answered by (1k points)

Usually you shouldn't have to do anything special. The new list should be recognized and mapped automatically

(https://manual.docs.microstream.one/data-store/legacy-type-mapping).

Did you call persist on the list in your code? Can you share your code?

commented by (220 points)

Dear Fred,
I've tried to make a simple example...

App.java:

package myapplication;

import one.microstream.storage.types.EmbeddedStorage;
import one.microstream.storage.types.EmbeddedStorageManager;
import java.nio.file.Paths;

public class App  {

	private static EmbeddedStorageManager storageManager = null;
    public static void main(String[] args) {
    	new App();
    	CarRepository.add("BMW");
    	CarRepository.add("Porsche");
    	//WheelRepository.add("Michelin");
    	CarRepository.printAll();

    	System.out.println(CarRepository.find("BMW"));
    	System.out.println(CarRepository.find("Rolls Royce"));
    	//System.out.println(WheelRepository.find("GoodYear"));
    	System.exit(0);
    	}

    public App() {
    	storageManager = EmbeddedStorage.start(new DataRoot(), Paths.get("data"));
    }
    public static DataRoot root() {
    	return (DataRoot)storageManager.root();
    }
    public static EmbeddedStorageManager getStorageManager() {
    	return storageManager;
    }
 
}

DataRoot.java

package myapplication;

import java.util.ArrayList;
import java.util.List;

public class DataRoot {
	private final List<Car> cars = new ArrayList<>();
	//private final List<Wheel> wheels = new ArrayList<>();
	public DataRoot() {
		super();
	}
	
	public List<Car> cars(){
		return this.cars;
	}
    //public List<Wheel> wheels(){
	//	return this.wheels;
	//}
}

Car.java

package myapplication;

public class Car {
	private String brand;
	
	public Car(final String brand)
	{
		super();
		this.brand = brand;
	}
	public String getBrand() {
		return this.brand;
	}
	public void setBrand(final String brand)
	{
		this.brand = brand;
	}
	@Override
	public String toString()
	{
		return this.brand;
	}
}

CarRepository.java

package myapplication;

import java.util.List;
import java.util.stream.Collectors;

public class CarRepository {
	private final static List<Car> cars = ((DataRoot) App.getStorageManager().root()).cars();

    public static void add(String value) {
    	cars.add(new Car(value));    
    	App.getStorageManager().store(cars);
    }

    public static void printAll() {
    	if (cars.isEmpty()) System.out.println("No cars");
    	else
    	{
    		for (int i=0, c=cars.size();i<c;i++) System.out.println(i+ " "+cars.get(i));
    	}
    }
    
    public static boolean find(String value) {
    	cars.stream()
    			.filter(car -> car.getBrand().equals(value))
    			.collect(Collectors.toList());
    	return cars.size() >0 ? true:false;
    }
}

When you run the above code, everything goes fine. The output is, as expected:
0 BMW
1 Porsche
true
true

However, if you take away the commented lines in App.java, DataRoot.java and add two classes

Wheel.java

package myapplication;

public class Wheel {
	private String brand;
	
	public Wheel(final String brand)
	{
		super();
		this.brand = brand;
	}
	public String getBrand() {
		return this.brand;
	}
	public void setBrand(final String brand)
	{
		this.brand = brand;
	}
	@Override
	public String toString()
	{
		return this.brand;
	}
}

and

WheelRepository.java

package myapplication;

import java.util.List;
import java.util.stream.Collectors;

public class WheelRepository {
	private final static List<Wheel> wheels = ((DataRoot) App.getStorageManager().root()).wheels();

    public static void add(String value) {
    	wheels.add(new Wheel(value));    
    	App.getStorageManager().store(wheels);
    }

    public static void printAll() {
    	if (wheels.isEmpty()) System.out.println("No cars");
    	else
    	{
    		for (int i=0, c=wheels.size();i<c;i++) System.out.println(i+ " "+wheels.get(i));
    	}
    }
    
    public static boolean find(String value) {
    	wheels.stream()
    			.filter(car -> car.getBrand().equals(value))
    			.collect(Collectors.toList());
    	return wheels.size() >0 ? true:false;
    }
 
}

and run the application again, then nothing happens with the wheels... the output becomes
0 BMW
1 Porsche
2 BMW
3 Porsche
true
true
true

NO errors...

What am I missing to get the second list into the database ?

Thanks in advance,

Hans.

commented by (1k points)
First of all your WheelRepository:
- You should call your variables wheel instead of car. But thats just copy/paste, not a bug.

- Your find Method does a filter, but the collected result list is not saved. Instead you ask for the full list of wheels for its size, which is a bug. The correct code would be:

List<Wheel> result = wheels.stream().filter(car -> car.getBrand().equals(value)).collect(Collectors.toList());
return result.size() > 0 ? true : false;

That way it should return false, as you saved a Michelin and searched for a GoodYear.

Finally you didnt call WheelRepository.printAll(); in your App class.
If you do so, you will get this output:

0 BMW
1 Porsche
0 Michelin
true
true
false

As you can see, Michelin was persisted. Does this help you?
Regards
commented by (220 points)
edited by

Dear Fred,

Thanks for your time. I've adapted the code as you indicated, and at first sight it seemed to work.
Running the program without 'Wheels', on an empty database; gave me following output:
 

0 BMW
1 Porsche
true
false

which is correct.

Then I added the 'Wheels', and ran the program again, which gave me following output

0 BMW
1 Porsche
2 BMW
3 Porsche
0 Michelin
true
false
false

Again, correct : 2 cars added, 1 wheel ... However, when I run the program again, I get 

0 BMW
1 Porsche
2 BMW
3 Porsche
4 BMW
5 Porsche
0 Michelin
true
false
false

2 cars added, but no wheel ?? 

Can you check this ?

Thanks !

Notes: Every question must be a separate forum post. Headline: Formulate your question shortly and precisely. Thank you!
Powered by Question2Answer
...