Get return value in Lambda function - java

I have a function call implemented using lambda which insert a row in postgres database using jooq library.
Below is the code:
dslContext.transaction(
c -> {
this.postgresService.insertData(c, table, map);
});
where c of type org.jooq.Configuration.
The code works properly & inserts a record in table & returns the inserted record. How can I access the
returned primary key out of the lambda function.
This is the function to insertData :
public Record insertData(
Configuration configuration, Table<? extends Record> table, Map<TableField<? extends Record, ?>, Object> map
)
{
return DSL.using(configuration)
.insertInto(table)
.set(map)
.returning()
.fetchOne();
}

Just use transactionResult:
String primaryKey = dslContext.transactionResult(
(Configuration c) -> {
return this.postgresService.insertData(c, table, map);
});

You could create a wrapper class for storing the retrieved value:
class PrimaryKeyWrapper{
Record primaryKey;
public void setPrimaryKey(Record primaryKey) {
this.primaryKey = primaryKey;
}
public Record getPrimaryKey() {
return primaryKey;
}
}
And use and instance of that class for store this value from inside the lambda function:
PrimaryKeyWrapper primaryKeyWrapper = new PrimaryKeyWrapper();
dslContext.transaction(
c -> {
Record primaryKey = this.postgresService.insertData(c, table, map);
primaryKeyWrapper.setPrimaryKey(primaryKey);
});
Finally you can obtain the value from outside:
primaryKeyWrapper.getPrimaryKey();

Related

How to get back a DTO Object from a procedure

I need to execute a procedure on my sql server database that will return me some fields and I wish to transform this fields directly in a List of my DTO Object that will be returned, but i'm new on spring boot and can't get it to work. I tried to do a Converter class but didnt understand much of how it works e probally did it wrong, here is my code on a way i wish it work:
public interface IMyDtoRepository extends JpaRepository<SomeEntity, Long> {
#Query(value = "EXECUTE MyProcedure :param1, :param2, :param3, :param4, :param5)")
public List<MyDtoObject> execMyProcedure(#Param(value = "param1") Integer param1,
#Param(value = "param2") String param2,
#Param(value = "param3") String param3,
#Param(value = "param4") String param4,
#Param(value = "param5") Integer param5);
}
The DtoObject
public class MyDtoObject{
// My Declared Fields...
public MyDtoObject() {
}
public MyDtoObject(/* My Fields */) {
// Setting fields
}
public MyDtoObject(Object[] objects) {
// Setting fields
}
// Getters n Setters...
I omitted the information that i didn't think it was necessary but i can give more explanation if need it
to map the result on your DtoObject with spring-data-jpa your can use : #SqlResultSetMapping
javadoc here
I have a similar method that I use in my DAL. It uses reflection and generics to convert a datatable to whatever type you pass in. Just pass in the datatable you get as a result of your procedure and you're good to go.
public List<T> ConvertDataToTypeList<T>(System.Data.DataTable DataTable) where T : class, new()
{
try
{
System.Type t_Object_Type = typeof(T);
ICollection<PropertyInfo> p_Properties;
lock (Properties_Dictionary)
{
if (!Properties_Dictionary.TryGetValue(t_Object_Type, out p_Properties))
{
p_Properties = t_Object_Type.GetProperties().Where(property => property.CanWrite).ToList();
Properties_Dictionary.Add(t_Object_Type, p_Properties);
}
}
System.Collections.Generic.List<T> l_List = new List<T>(DataTable.Rows.Count);
foreach (var v_Row in DataTable.AsEnumerable())
{
T o_Object = new T();
foreach (var prop in p_Properties)
{
var propType = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType;
var safeValue = v_Row[prop.Name] == null ? null : Convert.ChangeType(v_Row[prop.Name], propType);
prop.SetValue(o_Object, safeValue, null);
}
l_List.Add(o_Object);
}
return l_List;
}
catch
{
return new List<T>();
}
}

Hibernate Envers : How to check if a field has changed between two revisions?

I am using Hibernate envers to audit entities in my application. I have separate _audit tables for each entity and then in those tables I have _mod boolean column to indicate if the field has changed or not.
But, I m not getting how to use that column in queries or even how do I get this data in the code?
e.g. following code gives list of audited persons. How do I check which data has changed?
List person = getAuditReader().createQuery()
.forEntitiesAtRevision(Person.class, 12)
.getResultList();
You can loop through all the fields of the given entity and find out if that field is changed or not.
Sample code snippet to loop through all the fields of Person entity for revision number 12 and find value of fields which are updated.
public void processFields() throws Exception {
for (Field field : Person.class.getDeclaredFields()) {
final Person changedEntity = fetchEntityForRevisionWhenPropertyChanged(Person.class, 12, field.getName());
if (changedEntity != null) {
// Updated field value for the field. This will list all fields which are changed in given revision.
final Object fieldValue = getField(changedEntity, field.getName());
}
}
}
private <T> Object getField(final T object, final String fieldName) throws Exception {
return new PropertyDescriptor(fieldName, object.getClass()).getReadMethod().invoke(object);
}
private <T> T fetchEntityForRevisionWhenPropertyChanged(final Class<T> entityClass, final int revisionNumber, final String propertyName) {
final List<T> resultList = getAuditReader()
.createQuery()
.forEntitiesModifiedAtRevision(entityClass, revisionNumber)
.add(AuditEntity.property(propertyName).hasChanged())
.addOrder(AuditEntity.id().asc())
.getResultList();
if (CollectionUtils.isNotEmpty(resultList)) {
return resultList.get(0);
} else {
return null;
}
}
In any case if you want to find previous revison of your entity for comparision, you can use following method:
public T getPreviousVersion(final Class<T> entityClass, final Long entityId, final Long currentRevisionNumber) {
final AuditReader reader = AuditReaderFactory.get(entityManager);
final Number previousRevision = (Number) reader.createQuery()
.forRevisionsOfEntity(entityClass, false, true)
.addProjection(AuditEntity.revisionNumber().max())
.add(AuditEntity.id().eq(entityId))
.add(AuditEntity.revisionNumber().lt(currentRevisionNumber))
.getSingleResult();
return Optional.ofNullable(previousRevision)
.map(previousRev -> reader.find(entityClass, entityId, previousRev))
.orElse(null);
}
You can try to use Hibernate interceptors. Here is good article about interceptors.
With interceptor you can create a callback which would be executed on entity updates/creation etc. It would be smth like this:
public class EntityInterceptor extends EmptyInterceptor {
#Override
public boolean onFlushDirty(Object entity,
Serializable id,
Object[] currentState,
Object[] previousState,
String[] propertyNames,
Type[] types) {
if ( entity instanceof YourEntity ) {
//do update stuff
return true;
}
return false;
}
}
You can compare currentState with previousState to collect information about entity changes and persist it to other tables.

Android Firebase - Why Null Values in Map fields are ignored

I discovered when saving a POJO with a map field using Firebase on Android, that if that map contains nulls in the value property of that map, then the whole field is ignored.
The workaround is easy (non-null values will result in the map saving successfully), but I want to understand why is this so?
Model
public class Game {
private String owner;
private Map<String, String> characters;
public Game() {
// empty constructor for Firebase
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public Map<String, String> getCharacters() {
return characters;
}
public void setCharacters(Map<String, String> characters) {
this.characters = characters;
}
}
Calling code
final Game game = new Game();
game.setOwner("owner");
game.setCharacters(new HashMap<String, String>());
game.getCharacters().put("Bugs Bunny", null);
game.getCharacters().put("Batman", null);
final Firebase ref = new Firebase("<firebaseurl>/test/" + System.currentTimeMillis());
ref.setValue(game);
Resulting object in Firebase
{
"1456421340781": {
"owner": "owner"
}
}
They're actually not ignored. When you give Firebase a null value for a property/path, you indicate that you want to property or path to be deleted.
From the documentation on Firebase's JavaScript set() method:
Passing null for the new value is equivalent to calling remove(); all data at this location or any child location will be deleted.
So if you set a value with:
ref.child("keith").setValue(47649);
Then the following will delete it:
ref.child("keith").setValue(null);
This behavior is most useful when you use updateChildren(), but it works equally when you call setValue().

Transform Stream into a Map, when key/value mapping functions have a computational step in common

I have a collection of Employee objects and need to turn it into a map of hyperlink widgets for presentation purposes.
For each employee, an entry is added to the result, with the key being an identifier (here a National Insurance number), and the value being the hyperlink widget. Here's a first attempt:
static Map<String, Hyperlink> toHyperlinksByNIN(Collection<Employee> employees) {
return employees.stream()
.collect(Collectors.toMap(
Employee::determineUniqueNINumber,
employee -> new Hyperlink(
employee.getName(), employee.determineUniqueNINumber())));
}
Unfortunately, this solution won't do, because the NI number is actually not part of the employee model, but needs to be fetched from an expensive remote service on every call to Employee.determineUniqueNINumber. This method is simply too costly to call more than once per employee record.
How can I obtain the desired Map
doing a single pass through the collection using the Stream API,
while applying the common part in the key/value mapping functions (Employee.determineUniqueNINumber) only once per stream element?
Does Hyperlink class stores UniqueNINumber in instance field and expose getter method? Then you can first create Hyperlink object, and then create the map :
return employees
.stream()
.map(employee -> new Hyperlink(employee.getName(), employee
.determineUniqueNINumber()))
.collect(Collectors.toMap(Hyperlink::getUniqueNINumber, i -> i));
Here is Hyperlink class :
public class Hyperlink {
private String name;
private String uniqueNINumber;
public Hyperlink(String name, String uniqueNINumber) {
this.name = name;
this.uniqueNINumber = uniqueNINumber;
}
public String getName() {
return name;
}
public String getUniqueNINumber() {
return uniqueNINumber;
}
// Other stuff
}
As others have suggested, the easiest way is to map the elements of the stream to a container object so that you can then collect the cached NINumber from that container object together with the other details.
If you don't want to write your own custom class for every such use, you can utilize an existing type, such as AbstractMap.SimpleEntry.
You will then be able to write:
return employees.stream()
.map(emp -> new AbstractMap.SimpleEntry<>(emp.determineUniqueNINumber(),emp.getName()))
.collect(Collectors.toMap(
mapEntry -> mapEntry.getKey(),
mapEntry -> new Hyperlink(mapEntry.getValue(), mapEntry.getKey())));
This saves you writing your own class for a simple case like this. Of course, if you need more than just the getName() from Employee, your second element can be the Employee object itself.
I would go with caching but you can always create your own collector / use a custom reduction operation:
return employees.stream()
.collect(HashMap::new,
(map, e) -> {
String number = e.determineUniqueNINumber();
map.put(number, new Hyperlink( e.getName(), number));
},
Map::putAll);
I think the easiest solution to your problem is to implement a simple caching procedure inside the method determineUniqueNINumber:
public class Employee {
private String niNumber;
public String determineUniqueNINumber() {
if (niNumber == null) {
niNumber = resultOfLongAndCostlyMethod();
}
return niNumber;
}
}
This way, on the second call, the costly method is not called and you simply return the already calculated value.
Another solution is to store the insurance number inside a custom typed Tuple class. It would store the employee along with its insurance number.
static Map<String, Hyperlink> toHyperlinksByNIN(Collection<Employee> employees) {
return employees.stream()
.map(e -> new Tuple<>(e, e.determineUniqueNINumber()))
.collect(Collectors.toMap(
t -> t.getValue2(),
t -> new Hyperlink(t.getValue1().getName(), t.getValue2())));
}
class Tuple<T1, T2> {
private final T1 value1;
private final T2 value2;
public Tuple(T1 value1, T2 value2) {
this.value1 = value1;
this.value2 = value2;
}
public T1 getValue1() {
return value1;
}
public T2 getValue2() {
return value2;
}
}
You could transform to a helper data class to ensure that you only get the number once:
private static class EmployeeAndNINumber {
private Employee employee;
private String niNumber;
public EmployeeAndNINumber(Employee employee) {
this.employee = employee;
this.niNumber = employee.determineUniqueNINumber();
}
public Employee getEmployee() { return this.employee; }
public String getNINumber() { return this.niNumber; }
public Hyperlink toHyperlink() {
return new Hyperlink(employee.getName(), this.getNINumber());
}
}
Then you could transform to this data class, getting the NI number once and only once, then use that information to build up your map:
employees.stream()
.map(EmployeeAndNINumber::new)
.collect(toMap(EmployeeAndNINumber::getNINumber,
EmployeeAndNINumber::toHyperlink));

In-line View Definitions Couch Db Ektorp

I use Couch DB with Ektorp at Spring 3. I read the document and have tried to implement examples. I am so new to these technologies. This is the point where I didn't understand:
#View( name = "all", map = "function(doc) { if (doc.type == 'Sofa' ) emit( null, doc._id )}")
public class SofaRepository extends CouchDbRepositorySupport<Sofa> {
#View( name = "avg_sofa_size", map = "function(doc) {...}", reduce = "function(doc) {...}")
public int getAverageSofaSize() {
ViewResult r = db.queryView(createQuery("avg_sofa_size"));
return r.getRows().get(0).getValueAsInt();
}
}
How does that wievs work and how to define them, what happens at that lines?
CouchDbRepositorySupport out of the box provides the following methods to the SofaRepository:
public void add(Sofa entity);
public void update(Sofa entity);
public void remove(Sofa entity);
public Sofa get(String id);
public Sofa get(String id, String rev);
public List<T> getAll();
public boolean contains(String docId);
By having this inline view annotation for CouchDbRepositorySupport:
#View( name = "all", map = "function(doc) { if (doc.type == 'Sofa' ) emit( null, doc._id )}")
You redefine the return from a getAll() method.
You also adding another method getAverageSofaSize() to your repository, with inline View:
#View( name = "avg_sofa_size", map = "function(doc) {...}", reduce = "function(doc) {...}")
which explicitly provides a query that db.queryView(createQuery("avg_sofa_size")); undersntad. db here is a CouchDbConnector that is able to create, delete, purge, find, etc..
Take a look at more documentation about defining in line Views

Categories