Best way to set transient attribute on entity instance after Metadata.create - cuba-platform

I'm currently setting the result of a jpql query on a transient attribute of several instances of entities attached with composition using BeforeDetachEntityListener.
Since I'm also using Metadata.create to create them, I would like to be able to do the same operation after creating them. What's the best way to handle the situation?

You can set values at object creation time with #PostConstruct
public class MyEntity extends StandardEntity {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "USER_ID")
protected User creator;
#PostConstruct
protected void init() {
setCreator(AppBeans.get(UserSessionSource.class).getUserSession().getUser());
}
}
More information about how to initialize data in entities can be found in the docs at 5.8.3.1 Entity Fields Initialization and 5.8.3 Assigning Initial Values

Related

Optaplanner: problems with InverseRelationShadowVariable

have a many-1 relationship pupil-formGroup: pupils are assigned to a formGroup and a formGroup can contain many pupils. I have attempted to implement an InverseRelationShadowVariable having watched your video/tutorial https://www.youtube.com/watch?v=ENKHGBMDaCM (which does not quite correspond with the latest optaplanner documentation I realise)
FormGroup extracts
#Entity
#PlanningEntity
public class FormGroup {
#InverseRelationShadowVariable(sourceVariableName = "formGroup")
#OneToMany(mappedBy = "formGroup", fetch = FetchType.EAGER)
private List<Pupil> pupilList = new ArrayList<Pupil>();
public List<Pupil> getPupilList() {
return pupilList;
}
public Integer getPupilCount() {
return pupilList.size();
}
Pupil extracts
#Entity
#PlanningEntity
public class Pupil
#PlanningVariable(valueRangeProviderRefs = "formGroupRange")
#ManyToOne
private FormGroup formGroup;
Config extracts
<solutionClass>org.acme.optaplanner.domain.Plan</solutionClass>
<entityClass>org.acme.optaplanner.domain.Pupil</entityClass>
<entityClass>org.acme.optaplanner.domain.FormGroup</entityClass>
I believe I've followed the steps in the videoexactly (don't we all say that) but at solve time I get hundreds of errors... Repetitions of the following
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:774)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
Any hint gratefully received...
The InverseRelationShadowVariable creates a bi-directional relationship between the genuine planning entity (Pupil) and the planning value (FormGroup). This may become problematic if you re-use your planning domain classes for other purposes, such as ORM persistence or serialization.
In this case, Jackson is unable to serialize Pupil, because it references a FormGroup, which has a List containing a reference back to that Pupil. See? An endless loop.
Solve this issue by adding the #JsonIgnore annotation on top of your inverse relation property and breaking that loop for Jackson:
#Entity
#PlanningEntity
public class FormGroup {
#JsonIgnore // THIS IS THE FIX
#InverseRelationShadowVariable(sourceVariableName = "formGroup")
#OneToMany(mappedBy = "formGroup", fetch = FetchType.EAGER)
private List<Pupil> pupilList = new ArrayList<Pupil>();
public List<Pupil> getPupilList() {
return pupilList;
}
public Integer getPupilCount() {
return pupilList.size();
}
...

Create object of one type from object of another type with database lookups

I have an application that gets a car entity from a third party database. I call the entity ThirdPartyCar. My application needs to create a Car entity by using data from a ThirdPartyCar. However, the Car entity must also derive some of its data from my application's database. For example, a status of a ThirdPartyCar might be _BOUGHT and through a database lookup my application must transform to Sold.
I currently have a Car constructor that has a ThirdPartyCar argument. But the Car constructor cannot populate the lookup data since it is an entity and entities should not have a reference to a repositories. So, I also have a service to populate the remaining data:
public class ThirdPartyCar {
#Id
private Long id;
private String vin;
private String status;
// more props + default constructor
}
public class Car {
#Id
private Long id;
private String vin;
private CarStatus status;
// more props (some different than ThirdPartyCar) + default constructor
public Car(ThirdPartyCar thirdPartyCar) {
this.vin = thirdPartyCar.getVin();
// more props set based on thirdPartyCar
// but props leveraging database not set here
}
public class CarStatus {
#Id
private Long id;
private String status;
}
public class CarBuilderService {
private final CarStatusMappingRepository repo;
public Car buildFrom(ThirdPartyCar thirdPartyCar) {
Car car = new Car(thirdPartyCar);
CarStatus status = repo.findByThirdPartyCarStatus(thirdPartyCar.getStatus());
car.setStatus(status);
// set other props (including nested props) that depend on repos
}
}
The logical place to create a Car based on a ThirdPartyCar seems to be the constructor. But I have a disjointed approach b/c of the need of a repo. What pattern can I apply such that all data is created in the constructor but still not have the entity be aware of repositories?
You should avoid linking two POJO classes from different domains in constructor. These two classes should not know anything about each other. Maybe they represent the same concept in two different systems but they are not the same.
Good approach is creating Abstract Factory interface which will be used everywhere where Car should be created from ThirdPartyCar:
interface ThirdPartyCarFactory {
Car createNewBasedOn(ThirdPartyCar source);
}
and one implementation could be your RepositoryThirdPartyCarFactory:
class RepositoryThirdPartyCarFactory implements ThirdPartyCarFactory {
private CarStatusMappingRepository repo;
private CarMapper carMapper;
public Car createNewBasedOn(ThirdPartyCar thirdPartyCar) {
Car car = new Car();
carMapper.map(thirdPartyCar, car);
CarStatus status = repo.findByThirdPartyCarStatus(thirdPartyCar.getStatus());
car.setStatus(status);
// set other props (including nested props) that depend on repos
return car;
}
}
In above implementation you can find CarMapper which knows how to map ThirdPartyCar to Car. To implement this mapper you can use Dozer, Orika, MapStruct or your custom implementation.
Other question is how you got ThirdPartyCar object. If you load it by ID from ThirdPartyRepository you can change your abstract factory to:
interface CarFactory {
Car createNew(String id);
}
and given implementation loads by ID ThirdPartyCar and maps it to Car. Everything is hidden by factory which you can easily exchanged.
See also:
Performance of Java Mapping Frameworks

Deserializing IEnumerable with private backing field in RavenDb

I've been modeling a domain for a couple of days now and not been thinking at all at persistance but instead focusing on domain logic. Now I'm ready to persist my domain objects, some of which contains IEnumerable of child entities. Using RavenDb, the persistance is 'easy', but when loading my objects back again, all of the IEnumerables are empty.
I've realized this is because they don't have any property setters at all, but instead uses a list as a backing field. The user of the domain aggregate root can add child entities through a public method and not directly on the collection.
private readonly List<VeryImportantPart> _veryImportantParts;
public IEnumerable<VeryImportantPart> VeryImportantParts { get { return _veryImportantParts; } }
And the method for adding, nothing fancy...
public void AddVeryImportantPart(VeryImportantPart part)
{
// some logic...
_veryImportantParts.Add(part);
}
I can fix this by adding a private/protected setter on all my IEnumerables with backing fields but it looks... well... not super sexy.
private List<VeryImportantPart> _veryImportantParts;
public IEnumerable<VeryImportantPart> VeryImportantParts
{
get { return _veryImportantParts; }
protected set { _veryImportantParts = value.ToList(); }
}
Now the RavenDb json serializer will populate my objects on load again, but I'm curious if there isn't a cleaner way of doing this?
I've been fiddeling with the JsonContractResolver but haven't found a solution yet...
I think I've found the root cause of this issue and it's probably due to the fact that many of my entities were created using:
protected MyClass(Guid id, string name, string description) : this()
{ .... }
public static MyClass Create(string name, string description)
{
return new MyClass(Guid.NewGuid(), name, description);
}
When deserializing, RavenDb/Json.net couldn't rebuild my entities in a proper way...
Changing to using a public constructor made all the difference.
Do you need to keep a private backing field? Often an automatic property will do.
public IList<VeryImportantPart> VeryImportantParts { get; protected set; }
When doing so, you may want to initialize your list in the constructor:
VeryImportantParts = new List<VeryImportantPart>();
This is optional, of course, but it allows you to create a new class and start adding to the list right away, before it is persisted. When Raven deserializes a class, it will use the setter to overwrite the default blank list, so this just helps with the first store.
You certainly won't be able to use a readonly field, as it couldn't be replaced during deserialization. It might be possible to write a contract resolver or converter that fills an existing list rather than creating a new one, but that seems like a rather complex solution.
Using an automatic property can add clarity to your code anyway - as it is less confusing whether to use the field or the property.

QueryOver<IInterface> fetches all implementations

Nhibernate has a nice feature, which I have discovered coincidentally:
public interface IInterface {}
public class Impl1 : IInterface {}
public class Impl2 : IInterface {}
ISession session = sf.OpenSession();
session.QueryOver<IInterface>().List();
This will fetch me all Impl1 ans Impl2 objects (in case those classes are mapped). They need not be mapped as SubClassMaps, which leads me to the conclusion that NHibernate resolves the implementing classes all by itself.
Can anyone send me the link to documentation on this one? I know neither the name nor the technical background of this feature...
Thanks in advance!
Actually, this is just the way NHibernate does inheritance mapping.
In addition to the usage you described, you also have the ability to i.e. define a child collection on an object, using the base type and put any object of inherited type to the collection. For instance, you could have another entity containing a collection of your IInterface objects:
public class MyEntity
{
public IList<IInterface> MyCollection { get; set; }
}
Now you could put any object implementing IInterface into MyCollection, and NHibernate will persist them (if mapping is correct):
Impl1 i1 = new Impl1();
Impl2 i2 = new Impl2();
MyEntity entity = new MyEntity();
entity.MyCollection.Add(i1);
entity.MyCollection.Add(i2);
session.Save(entity);
However, the actual database usage (generated SQL) depends on the inheritance mapping strategy that you have defined, so get familiar with them first. You can read more in official documentation.

Ninject getting a generic type in ToMethod

I have a repository like this:
public class Repository<T> : IRepository<T> where T : class
{
private readonly ISession session;
public Repository(ISession session)
{
this.session = session;
}
}
I use NHQS and I usually do this to get a ISession object:
SessionFactory.For<T>().OpenSession();
How do I setup Ninject to create a session automatically for the requested type and bind it? I tried this but I don't know what to put in the For<>():
kernel.Bind(typeof(IRepository<>))
.To(typeof(Repository<>))
.WithConstructorArgument("session", SessionFactory.For<>().OpenSession());
Looks like I need to get the generic type being used and pass it in the For<>()
How do I do that?
You should'nt use WithConstructorArgument; create a binding for ISession instead.
kernel.Bind<ISession>.ToMethod(context => ....).InRequestScope();
You can get the IRepository<> type from context.Request.ParentRequest.Service. You can now extract the entity type using reflection. However, if you are using the same database for all entities then it is probably easier to return a general session for all repositories.