Spring data deleteBy query doesnt return deleted object - spring-data

In Spring-data-mongodb, can we return the single deleted object from query method of repository like below
public interface MyRepository extends MongoRepository<MyObject, String>{
Optional<MyObject> deleteByXAndY(String x, String y);
}
if there will be always single document that's get deleted by above query.
I tried it but it throws exception like cant convert Long to MyObject. I think only void, long or List or Stream are supported. Is there any way to achieve what I am trying to do?

Spring doesn't know that only one object can ever be deleted by this method, so it won't allow you to define it with a single result returned. After all, there is no guarantee in the "contract" you have defined here that there will only be one match. You should probably define the method to return a List and then just get the first object from the list if you are sure there will only be one.

Related

BeanWrapperFieldSetMapper alternative, to avoid setTargetType/setPrototypeBeanName

I need a way to get rid of fieldSetMapper.setTargetType because I do not want to add a POJO every time I have a new file to read. Is it possible?
Springbatch has a few FieldSetMapper implementations available out-of-the-box : Documentation (FieldSetMapper)
You can for example use a PassThroughFieldSetMapper to get a FieldSet object in your processor. You can do the same with an ArrayFieldSetMapper to get an array object.
But in your case, I think you need to implement your own FieldSetMapper. It could for example have a names property (with a setter) and a targetClass property (with a setter). Using Reflect, you could then cast the object to your desired class and call setters according to the names passed as arguments.
Here's what a FieldSetMapper looks like :
#Override
public Report mapFieldSet(FieldSet fieldSet) throws BindException {
T object;
object.setField(fieldSet.readString(0));
return object;
}
Here's what Reflect looks like :
Method method = object.getClass().getMethod(methodName);
method.invoke(object);

MongoDB C# Select specific columns

I know that MongoDb C# driver doesn't support projections so I searched a little bit and I found that many people uses a mongoCursor to perform such queries, I'm trying to select only specific fields and my code is the following:
public T GetSingle<T>(Expression<Func<T, bool>> criteria,params Expression<Func<T, object>>[] fields) where T : class
{
Collection = GetCollection<T>();
return Collection.FindAs<T>(Query<T>.Where(criteria)).SetFields(Fields<T>.Include(fields)).SetLimit(1).SingleOrDefault();
}
I got and custom repository for users on top of that:
public User GetByEmail(string mail, params Expression<Func<User, object>>[] fields)
{
return GetSingle<User>(x=>x.Email==mail,fields);
}
this is the usage:
_repository.GetByEmail(email, x=>x.Id,x=>x.DisplayName,x=>x.ProfilePicture)
but I'm getting the fields included in the parameter but also all the Enums,dates and Boolean values that are part of the class User, the values that are string and not included in the field list are null so that's fine
what can I do to avoid that?
By using SetFields, you can specify what goes through the wire. However, you're still asking the driver to return hydrated objects of type T, User in this case.
Now, similar to say an int, enum and boolean are value types, so their value can't be null. So this is strictly a C#-problem: there is simply no value for these properties to indicate that they don't exist. Instead, they assume a default value (e.g. false for bool and 0 for numeric types). A string, on the other hand, is a reference type so it can be null.
Strategies
Make the properties nullable You can use nullable fields in your models, e.g.:
class User {
public bool? GetMailNotifications { get; set; }
}
That way, the value type can have one of its valid values or be null. This can, however, be clumsy to work with because you'll have to do null checks and use myUser.GetMailNotifications.Value or the myUser.GetMailNotifications.GetValueOrDefault helper whenever you want to access the property.
Simply include the fields instead this doesn't answer the question of how to it, but there are at least three good reasons why it's a good idea to include them:
When passing a User object around, it's desirable that the object is in a valid state. Otherwise, you might pass a partially hydrated object to a method which passes it further and at some point, someone attempts an operation that doesn't make sense because the object is incomplete
It's easier to use
The performance benefit is negligible, unless you're embedding huge arrays which I would suggest to refrain from anyway and which isn't the case here.
So the question is: why do you want to make all the effort of excluding certain fields?

default JPA behavior for selecting non-existing entity

I'm writing some tests to make sure all the CRUD methods are working correctly. Every one of them are working fine, but it seems to be a little bit tricky to test the remove method.
In my test, I'm doing this:
// remove
a = dao.select(1); // previously inserted in the DB
dao.remove(a);
assertNull(dao.select(a.getId()));
And the DAO class (only select and remove):
#Override
public AtividadeComercial select(int id) {
return em.getReference(AtividadeComercial.class, id);
}
#Override
public void remove(AtividadeComercial e) {
EntityTransaction t = em.getTransaction();
boolean active = t.isActive();
if(!active)
t.begin();
em.remove(em.getReference(e.getClass(), e.getId()));
if(!active)
t.commit();
}
But the test is always throwing a javax.persistence.EntityNotFoundException on the line after remove. Is this the normal behavior or is something really wrong? Sorry if this seems to much obvious, but I couldn't find an answer to that.
getReference() will never return null. Read its documentation:
Get an instance, whose state may be lazily fetched. If the requested instance does not exist in the database, the EntityNotFoundException is thrown when the instance state is first accessed.
This method returns a proxy over an entity that is supposed to exist. It doesn't even make a database query to check if the entity exists: it assumes that it exissts. And if the proxy is initialized later, and the entity doesn't exist, then you'll get an EntityNotFoundException.

Custom ORMLite Persister to Return Wrapper Objects

I am writing an application which uses ORMLite to connect to a back-end database. Since the application will be run over VPN I am trying to minimize database calls.
In order to minimize database calls I have created a set of classes to wrap the values for each field. Each wrapper class stores the original value returned from the database and also a current value. This allows things like reverting to the original value, or checking whether the value is dirty (ie. only update the database if one or more fields are dirty).
The implication of this regarding ORMLite is that ORMLite never returns a null value when it queries the database (even if the database returns null). If there is a null value in the database it returns a fully initialized "wrapper" with the currentValue and originalValue variables set to null.
It seems that the right place to do this is in a custom persister such as (where StatefulIntegerProperty is the wrapper for the Integer):
public class StatefulIntegerPersister extends BaseDataType {
... misc. other code
#Override
public Object resultToSqlArg(FieldType fieldType, DatabaseResults results, int columnPos) throws SQLException {
Integer result = results.getInt(columnPos);
return new StatefulIntegerProperty((results.wasNull(columnPos)) ? null : result);
}
#Override
public Object sqlArgToJava(FieldType fieldType, Object sqlArg, int columnPos) throws SQLException {
return sqlArg;
}
#Override
public Object javaToSqlArg(FieldType fieldType, Object obj) throws SQLException {
return ((StatefulIntegerProperty)obj).getCurrentValue();
}
#Override
public boolean isStreamType() {
return true; // this is a hack to work around ORMLite setting the value to null in the FieldType.resultToJava function
}
}
I have three questions:
Is this the correct approach?
In the ORMLite FieldType.resultToJava function it seems to do a null check and will replace my wrapper with null if the database returned null. Right now I am getting past this by overriding the isStreamType method in the persister to return true. Is this the best approach, and will I find later an unintended negative side effect?
What is the difference between the resultToSqlArg and sqlArgToJava methods in a custom persister, and specifically, which one of these should I use to wrap the value returned from the DB, and then what should I be doing in the other?
Is this the correct approach?
I don't understand why anything that you are doing here minimizes database calls. Can you start a discussion on the users' mailing list?
Right now you are overriding the resultToSqlArg(...) method when I think you want the sqlArgToJava(...). See below.
Right now I am getting past this by overriding the isStreamType method in the persister to return true. Is this the best approach...
Hrm. If it works then fine but it seems dangerous to use this setting in this manner. If I changed the behavior of the isStreamType() method then this may break your code. At the very least you should have unit tests to confirm this behavior that will break if you upgrade ORMLite.
That said, there is good handling in the code specifically around null values if isStreamType() is true.
What is the difference between the resultToSqlArg and sqlArgToJava...
I've fleshed out the javadocs for these.
resultToSqlArg takes the object from the SQL results and turns it into a java-object suitable to be an argument to SQL commands. For example, if you have a date-long type, this will extract a Long value from the database results.
sqlArgToJava takes the sql-arg value and converts it into our Java field. For example, if you have a date-long type, this will take a Long value and convert it into a Date which matches the entity field.
I think you should override the sqlArgToJava and not the resultToSqlArg.

Spring List Binding in Form

I'm trying to bind a list/arraylist/hashmap/etc of custom objects to my form in JSP using Spring. Right now, the controller creates a Map of the two lists (Boolean list and custom object list) in referenceData(), and provides it to the form which uses those values to populate the fields. The values are initialized from a MySQL database using Hibernate, and all that works fine. The list is a known length before the form is initialized, so that part is easier. Now what I'd like to do is correctly bind those objects in the form, so that when there are changes made, I can detect that in onSubmit() (or wherever is appropriate), and update the database accordingly. I can't seem to bind them correctly in the form so that I can see changes made. I tried just using a list of the form fields as the model, but even that wasn't working correctly. Do I just need to inject the list in a particular way? Any ideas or examples here? Any help would be greatly appreciated.
UPDATE: At Ralph's request here is the solution I used:
In my data object class, I lazy loaded a map using MapUtils.lazyMap(), with a String key and other custom object value. The other custom object is just a class that contains List<String> and getters/setters. In the corresponding .jsp file, I just nest several loops to loop through the keys first using loop.current.key and then loop2.current.value.paramsList to loop through the values for that key. This was not really what I asked for in my original post, as I was looking for a more general solution, and the lazy loading pointed me in the right direction.
In Spring 2 you need a special List in your Command object, that is able to grow if one add the x-th element event if the list has not this size yet.
One way to do that is to use LayzList decorator from commons-collections.
#Override
protected Object formBackingObject(final HttpServletRequest request)
throws Exception {
List<PosterSelectionRow> posterSelectionRowList = LazyList.decorate(
new ArrayList<PosterSelectionRow>(),
new PosterSelectionRowListFactory());
return new PosterSelectionCommand(posterSelectionRowList);
//PosterSelectionCommand contains a list of selected poster rows
}
private static class PosterSelectionRowListFactory
implements org.apache.commons.collections.Factory {
/** Invoked if the list need a new element */
public Object create() {
return = new PosterSelectionRow();
}
}
When I remember right, there is a way without that Factory stuff, but I am not sure.