Inject anything other than param value - spring-data-couchbase

I'm trying to inject anything other than values using the #Query N1QL query syntax but can't get it to work.
Here is the pure N1QL query:
SELECT * from `my-bucket` WHERE _class = 'my.package.MyModel' AND myParam = 'myValue'
I successfully manage to inject a value in Java and get the correct results:
// In my repository
#Query("#{#n1ql.selectEntity} WHERE myParam = $1 AND #{#n1ql.filter}")
Collection<MyModel> myCustomSearch(String value);
// In my business code
myRepository.myCustomSearch("myValue");
However I can't manage to inject anything else (like a param). This doesn't work:
// In my repository
#Query("#{#n1ql.selectEntity} WHERE $1 = 'myValue' AND #{#n1ql.filter}")
Collection<MyModel> myCustomSearch(String param);
// In my business code
myRepository.myCustomSearch("myParam");
Considering that in a pure N1QL query, the value usually is wrapped in single quotes ('') and it's not necessary when injecting it, I'm afraid spring-data-couchbase always wraps injected elements with single or double quotes (thus my query is transformed into
SELECT * from `my-bucket` WHERE _class = 'my.package.MyModel' AND 'myParam' = 'myValue'
which explains why Couchbase doesn't return any result).
Did I miss something? Otherwise, is there a way to bypass the quote injection from spring-data-couchbase?
I am aware I could simply use a com.couchbase.client.java.Bucket and call query on it, but this loses the whole point of spring-data-couchbase for me, which is to always manipulate POJOs and hide the JSON manipulation.
I appreciate any help!

$1 is actually just using the N1QL syntax for parameterized statements. I haven't extensively tested it, but you could use SpEL here. The way to use a method parameter in SpEL is to use the #{[x]} syntax where x is the 0-based index of the parameter to use.
Careful when mixing the two approaches though: as soon as a $x is detected in the statement, Spring Data Couchbase will use all method arguments as the array to populate $x placeholders. So the first argument will map to $1, the second to $2, etc...
So to use both syntax (one to dynamically choose a field name, the other to let N1QL inject the searched value) you'd have to write something like:
#Query("#{#n1ql.selectEntity} WHERE #{[0]} = $2 AND #{#n1ql.filter}")
public List<Entity> findAllBySomeCriteria(String fieldName, String value);
Notice how #{[0]} and $1 will both point to the fieldName parameter, so the N1QL placeholder used is $2, that points to value.

Edit: See #simon-baslé 's answer, even shorter and more elegant than mine.
I think I found the best solution for my needs, in the form of implementing a custom method in my repository.
public interface MyRepositoryCustom {
Collection<MyModel> customN1qlQuery(String query);
}
public interface MyRepository extends CrudRepository<MyModel, String>, MyRepositoryCustom { }
public class MyRepositoryImpl implements MyRepositoryCustom {
#Autowired
RepositoryOperationsMapping templateProvider;
#Override
public Collection<MyModel> customN1qlQuery(String query) {
CouchbaseOperations template = templateProvider.resolve(MyRepository.class, MyModel.class);
return template.findByN1QL(N1qlQuery.simple(query), MyModel.class);
}
}
// In my business code
Collection<MyModel> result = myRepository.customN1qlQuery("select META().id AS _ID, META().cas AS _CAS, * from `" + bucket.name() + "` where _class = '"
+ MyModel.class.getCanonicalName() + "' and " + myCustomParam + " = '" + myCustomValue + "'");
I keep manipulating POJOs, yet I have full control over the N1QL query statement. The only (minor) drawback is that I can no longer inject Spring SpEL syntax (like #{#n1ql.selectEntity} to retrieve the full entity, or #{#n1ql.filter} to filter on the entity class name). I found literal equivalent (as shown in my example above), so I can live with that.

Related

Disassemble links into entities in Spring Hateoas

maybe another one stumbled upon this topic and found a nice solution. Using the HATEOAS REST approach with help of Spring HATEOAS project works pretty well for link building to resources. But in the end, to map flattened resources back to an entity object tree, I need to disassemble my link and query the persistence backend. Example given, I have an entity Item, referencing ItemType (Many-to-one). Natural key of item is the composite of ItemType foreign key and Item code itself. The URL I map in ItemController using the link builder is
#RequestMapping("/catalog/items/{itemTypeCode}_{itemCode}")
Now a unique link for an item is e.g. http://www.sample.com/catalog/items/p_abc123
To invert this link I do some very ugly string work:
#Override
public Item fromLink(Link link) {
Assert.notNull(link);
String baseLink = linkTo(ColorTypeController.class).toString() + "/";
String itemTypeAndItemPart = link.getHref().replace(baseLink, "");
int indexOfSplit = itemTypeAndItemPart.indexOf('_');
ItemType itemType = new ItemType();
itemType.setCode(itemTypeAndItemPart.substring(0, indexOfSplit));
Item item = new Item();
item.setItemType(itemType);
item.setCode(itemTypeAndItemPart.substring(indexOfSplit + 1));
return item;
}
And all the time I am wondering, If there isn't a much nicer and more flexible approach (beware of any query string part, that will break the code) to do this inverse mapping. I actually do not want to call another MVC controller from within a controller but it would be nice, to somehow utilize the dispatcher servlet disassembly functions to deconstruct the URL into something more handy to work with. Any helpful hints for me? Thx alot :)
You can use a UriTemplate. Its match method returns a map of variables and their values that have been extracted from the URI. For example:
UriTemplate uriTemplate = new UriTemplate("/catalog/items/{itemTypeCode}_{itemCode}");
Map<String, String> variables = uriTemplate.match("http://www.sample.com/catalog/items/p_abc123");
String itemTypeCode = variables.get("itemTypeCode"); // "p"
String itemCode = variables.get("itemCode"); // "abc123"

Display nested list with doctrine2 and zf2

Following this tutorial and putting in all together to make it work in my project, just to display a nested list (using doctrine 2 and zf2) , I can not enter into the foreach. Using this snippet of code:
$root_categories = $em->getRepository('Controleitor\Model\Entity\Category')->findBy(array('parent_category' => null));
$collection = new \Doctrine\Common\Collections\ArrayCollection($root_categories);
$category_iterator = new \MYMODULE\Model\Entity\RecursiveCategoryIterator($collection);
$recursive_iterator = new \RecursiveIteratorIterator( $category_iterator, \RecursiveIteratorIterator::SELF_FIRST);
foreach ($recursive_iterator as $index => $child_category){
echo 'test';
}
Debug::dump($recursive_iterator);die;
I'm expecting to print the 'test' string but it only print this:
object(RecursiveIteratorIterator)#414 (0) {}
But when I do before the dump:
$recursive_iterator->current()->getTitle();
I got the title.. It fails somehow looping the \Doctrine\Common\Collections\ArrayCollection object.
If you're using different Debug class instead of Doctrine's one, that may the suspect. Try Doctrine\Common\Util\Debug::dump().
Explain comes from official documentation:
Lazy load proxies always contain an instance of Doctrine’s
EntityManager and all its dependencies. Therefore a var_dump() will
possibly dump a very large recursive structure which is impossible to
render and read. You have to use Doctrine\Common\Util\Debug::dump() to
restrict the dumping to a human readable level. Additionally you
should be aware that dumping the EntityManager to a Browser may take
several minutes, and the Debug::dump() method just ignores any
occurrences of it in Proxy instances.
I had the same issue. I've discussed with the author of this tutorial, he recommended me to check the valid() function of the RecursiveCategoryIterator class and there was the problem.
Since I was using "use" statetment and left a backslash before th class name:
use Entity\Category;
use Doctrine\Common\Collections\Collection;
class RecursiveCategoryIterator implements \RecursiveIterator
{
//.......
public function valid()
{
return $this->posts->current() instanceof \Category;
}
There ware two ways to solve this problem:
1. To remove the backslash:
return $this->posts->current() instanceof Category;
2. To use full namespace:
use Entity\Category; // remove this line
//.......
return $this->posts->current() instanceof \Entity\Category;
Hope that helps.

LINQ and web service cannot return anonymous types, and you cannot construct an object in a query?

Web services cannot return an anonymous type.
If you are building a LINQ query using classes through a datacontext... you cannot construct instances of those classes in a query.
Why would I want to do this? Say I want to join three "tables" or sets of objects. I have three items with a foreign key to each other. And say the lowest, most detailed of these was represented by a class that had fields from the other two to represent the data from those. In my LINQ query I would want to return a list of the lowest, most detailed class. This is one way I have decided to "join some tables together" and return data from each of them via LINQ to SQL via a WebService. This may be bad practice. I certainly do not like adding the additional properties to the lowest level class.
Consider something like this... (please ignore the naming conventions, they are driven by internal consideration) also for some reason I need to instantiate an anonymous type for the join... I don't know why that is... if I do not do it this way I get an error...
from su in _dataContext.GetTable<StateUpdate>()
join sfs in _dataContext.GetTable<SystemFacetState>()
on new { su.lngSystemFacetState } equals new { lngSystemFacetState = sfs.lngSystemFacetState }
join sf in _dataContext.GetTable<SystemFacet>()
on new { sfs.lngSystemFacet } equals new { lngSystemFacet = sf.lngSystemFacet }
join s in _dataContext.GetTable<System>()
on new { sf.lngSystem } equals new {lngSystem = s.lngSystem}
select new
{
lngStateUpdate = su.lngStateUpdate,
strSystemFacet = sf.strSystemFacet,
strSystemFacetState = sfs.strSystemFacetState,
dtmStateUpdate = su.dtmStateUpdate,
dtmEndTime = su.dtmEndTime,
lngDuration = su.lngDuration,
strSystem = s.strSystem
}
).ToList();
Notice I have to build the anonymous type which is composed of pieces of each type. Then I have to do something like this... (convert it to a known type for transport via the web service)
result = new List<StateUpdate>(from a in qr select(new StateUpdate
{
lngStateUpdate = a.lngStateUpdate,
strSystemFacet = a.strSystemFacet,
strSystemFacetState = a.strSystemFacetState,
dtmStateUpdate = a.dtmStateUpdate,
dtmEndTime = a.dtmEndTime,
lngDuration = a.lngDuration,
strSystem = a.strSystem
}));
It is just awful. And perhaps I have created an awful mess. If I am way way off track here please guide me to the light. I feel I am missing something fundamental here when I am adding all these "unmapped" properties to the StateUpdate class.
I hope someone can see what I am doing here so I can get a better way to do it.
You can create a 'dto' class which just contains the properties you need to return and populate it instead of the anonymous object:
public class Result
{
public string lngStateUpdate
{
get;
set;
}
... // other properties
}
then use it like this:
from su in _dataContext.GetTable<StateUpdate>()
...
select new Result
{
lngStateUpdate = su.lngStateUpdate,
... // other properties
}
Nitpick note - please ditch the Hungarian notation and camel casing for properties :)
I think the answer is to create another object to serve as a DTO. This object would not be mapped to the data context and can contain fields that cross the mapped objects. This solves the problems of repetitive properties in the mapped objects, and allows for instantiation of the DTO class in the query as it is not mapped.
FYI: with respect to the problem with the join- I revisited that and I think I may have had the inner and outer components of the join switched around before.

Linq using predicate not working

I've created a small test class, that returns data from an xml file.
I now want to make it more dynamic using linq but cannot get it to work.
public class LenderCollection
{
string fileName = "C:\\Lenders.xml";
public IEnumerable<Lender> Lenders { get; set; }
public void FetchLenders(Expression<Func<Lender, bool>> predicate = null)
{
IEnumerable<Lender> lenders = XmlHelper.GetObjectFromXml<List<Lender>>(fileName, "AllLenders");
Lenders = predicate.IsNotNull() ? lenders.Where(predicate) : lenders;
}
}
Visual Studio is giving an error on the section "lenders.Where(predicate)" - the message is "... does not contain a definition for Where..."
Any ideas what I'm doing wrong?
* UPDATE *
It seems to be something to do with the predicate - .Where is avaialable otherwise.
There's no extension method Where that extends IEnumerable<T> and takes a parameter of type Expression<Func<T, bool>>.
You have two options:
Use an IQueryable<Lender> instead of IEnumerable<Lender> (you can this easily by just calling .AsQueryable()) if you wan to keep the parameter predicate as Expression<Func<Lender, bool>>
Use the type Func<Lender, bool> instead of Expression<Func<Lender, bool>> for the predicate parameter. Since you're loading your data from a file, there's no point in using an IQueryable over an IEnumerable.
It's complaining that whatever type lenders is does not have a .Where method. This is either because:
You haven't included using System.Linq;
The type of lenders isn't an IEnumerable or similar.
Replace:
lenders.Where(predicate)
With:
lenders.ToList().Where(predicate)
Both should be able to return IEnumerable.
The main downfall with this is that the query will execute on the .ToList() command. I guess this is down to what you expect your function to be doing though, and if this is acceptable for your needs.

best way to store / lookup name value pairs

I have a list of error codes I need to reference, kinda like this:
Code / Error Message
A01 = whatever error
U01 = another error
U02 = yet another error type
I get the Code returned to me via a web service call and I need to display or get the readable error. So I need a function when passed a Code that returns the readable description. I was just going to do a select case but thought their might be a better way. What is the best way / most effieient way to do this?
Use a Dictionary, (in C#, but the concept and classes are the same):
// Initialize this once, and store it in the ASP.NET Cache.
Dictionary<String,String> errorCodes = new Dictionary<String,String>();
errorCodes.Add("A01", "Whatever Error");
errorCodes.Add("U01", "Another Error");
// And to get your error code:
string ErrCode = errorCodes[ErrorCodeFromWS];
You would use a dictionary. A dictionary uses a hashmap internally for performance, so it is good in that regard. Also, because you want this to go as quickly as possible by the sounds of it, I would statically initialize it in its own class instead of, for example, in an XML file or slimier. You would probably want something like:
public static class ErrorCodes
{
private static Dictonary<string, string> s_codes = new Dicontary<string, string>();
static ErrorCodes()
{
s_codes["code"] = "Description";
s_codes["code2"] = "Description2";
}
public static string GetDesc(string code)
{
return s_codes[code];
}
}
That way, if you wanted to move the back end to a file instead of being static, then you could.

Resources