-
Notifications
You must be signed in to change notification settings - Fork 4
Tutorial 6: Creating data generation plan
Till tutorial 5, we have configured JPAContextFactory with custom dependencies, generators, triggers and preconditions. Now from JPAContextFactory we will create JPAContext.
final JPAContextFactory jpaContextFactory
= JPAContextFactory.newInstance(Database.MY_SQL, entityManager);
jpaContextFactory.with(generator);
jpaContextFactory.with(dependencies);
jpaContextFactory.withPreconditions(...);
jpaContextFactory.withTriggers(...);
final JPAContext jpaContext = jpaContextFactory.create();
To explain with a simple example, let us say that we want to create following table data
-
Account
-
Person
-
Employee (extends Person)
final CreationPlan creationPlan = jpaContext.create(Plan.create() .add(Entity.of(Account.class)) .add(Entity.of(Employee.class)));
This would create a creation plan with 3 entities (Account, Person, Employee). Since Employee has a foreign key relation with Person, you don't need to explicitly specify Person in the Plan
Now you have a creationPlan, so lets have a look at what we are going to create...
creationPlan.print(new Printer() {
@Override
public void print(String s) {
System.out.println(s);
}
});
You will get a tree printed on the console
*******
└── *ROOT*
└── com.github.kuros.sample.entity.Account|0
└── com.github.kuros.sample.entity.People|0
└── com.github.kuros.sample.entity.Employee|0
In the plan, you need to specify the attributes for which you want null values to be set. By default, if not specified some random value will be assigned to all the attributes of entity.
final CreationPlan creationPlan = jpaContext.create(Plan.create()
.add(Entity.of(Person.class))
.withNullValues(Person_.lastName));
This would set null values for person's lastName.
We have seen preconditions at system level, in the similar way, we have preconditions to enforce order at plan level.
Let us take the our previous example
final CreationPlan creationPlan = jpaContext.create(Plan.create()
.add(Entity.of(Account.class))
.add(Entity.of(Employee.class)));
/* creationPlan would print
*******
└── *ROOT*
└── com.github.kuros.sample.entity.Account|0
└── com.github.kuros.sample.entity.Person|0
└── com.github.kuros.sample.entity.Employee|0
*/
let us just reverse the plan, and the creation order differs, so it would generate
final CreationPlan creationPlan = jpaContext.create(Plan.create()
.add(Entity.of(Employee.class))
.add(Entity.of(Account.class)));
/* creationPlan would print
*******
└── *ROOT*
└── com.github.kuros.sample.entity.Person|0
└── com.github.kuros.sample.entity.Employee|0
└── com.github.kuros.sample.entity.Account|0
*/
Now we want Account to be created before creating Person, so to achieve it, we will add preconditions
final CreationPlan creationPlan = jpaContext.create(Plan.create()
.add(Entity.of(Employee.class))
.add(Entity.of(Account.class))
.add(Entity.of(Person.class).createBefore(Account.class)));
/* creationPlan would print
*******
└── *ROOT*
└── com.github.kuros.sample.entity.Account|0
└── com.github.kuros.sample.entity.Person|0
└── com.github.kuros.sample.entity.Employee|0
*/
We want to create Entities with some specific values at the time of creating plan.
final CreationPlan creationPlan = jpaContext.create(Plan.create()
.add(Entity.of(Account.class).with(Account_.accountType, "Saving")));
Note: If id is provided, random-JPA would execute a findById query and load the data. So other values provided would not be persisted
Let us say that we want to create two different Employees referring to single Person.
Plan plan = Plan.create()
.add(Entity.of(Employee.class, 2).with(Employee_.Country, INDIA))
.add(Entity.of(Person.class).with(Person_.gender, "Male");
CreationPlan creationPlan = jpaContext.create(plan);
/*
└── *ROOT*
└── com.github.kuros.sample.entity.Person|0
├── com.github.kuros.sample.entity.Employee|0
└── com.github.kuros.sample.entity.Employee|1
*/
The numeric values represents the index number, using which entities can be accessed. We will see this details in the next section.
I would like to have a pizza with two cheese & 2 olives
jpaContext.create(Entity.of(Pizza.class),
Entity.of(Cheese.class , 2),
Entity.of(Olives.class, 2));
/*
└── *ROOT*
└── (h=1) com.github.kuros.sample.entity.Pizza|0
├── (h=0) com.github.kuros.sample.entity.Olives|0
│ ├── (h=0) com.github.kuros.sample.entity.Cheese|0
│ └── (h=0) com.github.kuros.sample.entity.Cheese|1
└── (h=0) com.github.kuros.sample.entity.Olives|1
├── (h=0) com.github.kuros.sample.entity.Cheese|2
└── (h=0) com.github.kuros.sample.entity.Cheese|3
*/
Something went wrong... (expecting 2 cheese but got 4 cheese??)
Here is how Random-JPA works: It generates graph of entities based on dependencies
Pizza
/ \
Olives Cheese
Then merges the graph to generate order, since Olives & Cheese both are at same height, it could generate:
Pizza Pizza
| |
Olives OR Cheese
| |
Cheese Olives
Now when you said a pizza with 2 olives & 2 cheese, it would generate, something like this:
Pizza Pizza
/ \ / \
/ \ / \
/ \ / \
Olives Olives Cheese Cheese
/ \ / \ / \ / \
/ \ / \ / \ / \
Cheese Cheese Cheese Cheese Olives Olives Olives Olives
So When you want a pizza with 2 olives & 2 cheese, you can simply say:
jpaContext.create(Entity.of(Pizza.class),
Entity.of(Cheese.class , 2),
Entity.of(Olives.class, 1))
/*
But it can generate
└── *ROOT*
└── (h=1) com.github.kuros.sample.entity.Pizza|0
└── (h=0) com.github.kuros.sample.entity.Olives|0
├── (h=0) com.github.kuros.sample.entity.Cheese|0
└── (h=0) com.github.kuros.sample.entity.Cheese|1
OR
└── *ROOT*
└── (h=1) com.github.kuros.sample.entity.Pizza|0
├── (h=0) com.github.kuros.sample.entity.Cheese|0
│ └── (h=0) com.github.kuros.sample.entity.Olives|0
└── (h=0) com.github.kuros.sample.entity.Cheese|1
└── (h=0) com.github.kuros.sample.entity.Olives|1
*/
To Fix this we should use createAfter/createBefore to make sure Cheese is always created before Olives, this would force a Cheese to be virtual parent of olives, now this would ensure you have correct order & tree.
jpaContext.create(Entity.of(Pizza.class),
Entity.of(Olives.class, 1),
Entity.of(Cheese.class , 2).createBefore(Olives.class)
)
/*
└── *ROOT*
└── (h=2) com.github.kuros.random.jpa.testUtil.entity.Pizza|0
├── (h=1) com.github.kuros.random.jpa.testUtil.entity.Cheese|0
│ └── (h=0) com.github.kuros.random.jpa.testUtil.entity.Olives|0
└── (h=1) com.github.kuros.random.jpa.testUtil.entity.Cheese|1
└── (h=0) com.github.kuros.random.jpa.testUtil.entity.Olives|1
*/