Is there a way to ask for a result to be sorted but not paginated ?
I have this:
public interface SampleRepository extends PagingAndSortingRepository<Sample, Integer> {
}
but when calling http://localhost:8080/data/samples?sort=name,desc the result is automatically paginated, but I do not want it paginated.
PagingAndSortingRepository offers the Iterable<T> findAll(Sort sort) method, that Returns all entities sorted by the given options.
Simply declare your SampleRepository like this:
public interface SampleRepository extends PagingAndSortingRepository<Sample, Integer> {
List<Sample> findAll(Sort sort)
}
That's what JpaRepository does, for instance.
http://localhost:8080/data/samples?sort=name,desc should then be mapped against SampleRepository.findAll(Sort sort) and beahve as you want it to.
If it's not the case, you can also add a findBy* method:
#RestResource(path = "asList", rel = "asList")
public List<Sample> findAllAsList(Sort sort);
and call http://localhost:8080/data/samples/search/asList/samples?sort=name,desc
Related
I would like to know how we can design .net core api controller to accept an array value like given below
http://localhost:32656/api/Values?str[]="abc"&str[]="xyz"
I did some research online and the only two options, I was able to find is either I need to pass indexes inside the array
eg:- http://localhost:32656/api/Values?str[0]="abc"&str[1]="xyz" (Pass indexes inside the array)
or I need to pass the array as repeated query strings.
eg:- http://localhost:32656/api/Values?str="abc"&str="xyz" (Pass it as repeated query strings)
But I would like to see the other possible options to send an array to .net core 2.1 api controller.
You can take advantage of the FromQuery attribute here, specifying the Name property as str[]:
public IActionResult Values([FromQuery(Name = "str[]")] List<string> strValues)
{
...
}
If you also want to strip out the "s for each value, you can use a Select. Here's a an example:
public IActionResult Values([FromQuery(Name = "str[]")] List<string> strValues)
{
var strValuesWithoutQuotes = strValues.Select(x => x.Trim('"'));
...
}
Here is how we do it:
[Route("api/v1/[controller]")]
public class TestController : Controller
{
[HttpGet]
public async Task Get(List<string> stringValues)
{
...
}
}
Then call the endpoint with http://localhost/api/v1/test?stringValues=string1&stringValues=string2
stringValues should have the list of values in the query string
I have something like this in my repository class in a Spring project:
#Query(value = "SELECT * FROM accounts WHERE (first_name LIKE %:firstName% AND last_name LIKE %:lastName%)", nativeQuery = true)
public List<Account> searchByFirstnameAndLastname(#Param("firstName")String firstName,#Param("lastName")String lastName);
I want it to return everything if the parameters are not provided. Even the ones with null firstname/lastname. And it ignores the null values because of the wildcard used. Since null is different from ''.
I was thinking of an if-statement structure and building the query in runtime based on the provided parameters and then setting the value for the #Query annotation.
I tried generating the where clause and passing it as a parameter but it didn't work. I guess the way Spring Data JPA processes the value of this annotation caused it.
Any idea what is the best solution to this?
Have you tried containing keyword like below :
List<Account> findByFirstnameContainingAndLastNameContaining(String firstName,String lastName);
Docs: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/
You cannot go far with #Query
For dynamic queries(with many optional filters), the way to go is using Criteria API or JPQL. I suggest the Criteria API as it is object oriented and suitable for dynamic queries.
I would suggest to use QueryDSL. It is mentioned in the docs JB Nizet already posted. There is is nice but quite old tutorial here.
With QueryDSL it is very convenient to create your queries dynamically and it is easier to understand than the JPA Criteria API.
The only difficulty in using QueryDSL is the need to automatically create the query objects from your entities but this can be automated by using maven.
There are two ways to handle your situation.
The hard way is using RepositoryFactoryBean as follow
create a custom RepositoryFactoryBean
public class DaoRepositoryFactoryBean, T, I extends Serializable>
extends JpaRepositoryFactoryBean
{
#Override
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager)
{
return new DaoRepositoryFactory(entityManager);
}
private static class DaoRepositoryFactory<E extends AbstractEntity, I extends Serializable> extends JpaRepositoryFactory
{
private EntityManager entityManager;
public DaoRepositoryFactory(EntityManager entityManager)
{
super(entityManager);
this.entityManager = entityManager;
}
#Override
protected Object getTargetRepository(RepositoryMetadata metadata)
{
return new DaoImpl<E>((Class<E>) metadata.getDomainType(), entityManager);
}
#Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata)
{
return Dao.class;
}
}
}
create Dao interface
#NoRepositoryBean
public interface Dao extends JpaRepository
{
List findByParamsOrAllWhenEmpty();
}
create your implementation
#Transactional(readOnly = true)
public class DaoImpl extends SimpleJpaRepository implements Dao
{
private EntityManager entityManager;
public DaoImpl(Class<E> domainClass, EntityManager em)
{
super(domainClass, em);
this.entityManager = em;
this.domainClass = domainClass;
}
List<E> findByParamsOrAllWhenEmpty()
{
//implement your custom query logic
//scan your domainClass methods for Query anotations and do the rest
}
}
introduce it to Spring Jpa Data
jpa:repositories
base-package=""
query-lookup-strategy="" factory-class="com.core.dao.DaoRepositoryFactoryBean"
The easy way using Custom Impl which in this case you can't use #Query annotation.
"coalesce" on MySQL or "IsNull" on SQL Server is my preferred solution. They return back the first non-null value of a list and you may use it as a trick to deal with an empty string just like a null:
#Query(value = "SELECT * FROM accounts WHERE (COALESCE(first_name,'') LIKE %:firstName% AND COALESCE(last_name,'') LIKE %:lastName%)", nativeQuery = true)
public List<Account> searchByFirstnameAndLastname(#Param("firstName")String firstName,#Param("lastName")String lastName);
Thanks to the questioner and the answerer :D at this page:
like '%' does not accept NULL value
I have a factory method class that returns a cache system class (pseudo code):
class CacheFactory
{
public static function get($type) {
switch ($type) {
case 'memcache':
return new Memcache();
case 'redis':
return new Redis();
case 'default':
return new Void();
}
}
}
The cache classes implements simple get() and set() methods (it uses an abstract class defining the common methods) that allows me to easily switch cache systems if needed. The normal use will be like:
$cache = CacheFactory::get('redis');
$value = $cache->get('key');
...etc
I want to have a setting to enable/disable the cache, but I don't want to add conditionals in the code asking if the cache is enabled or not everywhere. So I was thinking in returning a Void() object that implements the abstract class methods so it will be used when the cache is disabled, the class will look like this:
class Void extends ACache
{
public function get(){};
public function set(){};
}
Would this be a good approach? How would you think will be the best way to handle the enabled/disabled setting without adding conditionals in the actual implementation?
Thanks!
I have Model_Group that extends ORM.
I have Controller_Group that gets a new ORM:
public function before()
{
global $orm_group;
$orm_group = ORM::factory('Group');
}
...and it has various methods that use it to get different subsets of data, such as...
public function action_get_by_type()
{
global $orm_group;
$type = $this->request->param('type');
$result = $orm_group->where('type', '=', $type)->find_all();
}
Then I have another controller (in a separate module) that I want to use to manipulate the object and call the relevant view. Let's call it Controller_Pages.
$orm_object = // Get the $result from Controller_Group somehow!
$this->template->content = View::factory( 'page1' )
->set('orm_object', $orm_object)
What is the best way to pass the ORM object from Controller_Group to Controller_Pages? Is this a good idea? If not, why not, and what better way is there of doing it?
The reason for separating them out into different controllers is because I want to be able to re-use the methods in Controller_Group from other modules. Each module may want to deal with the object in a different way.
This is the way I would do it, but first I would like to note that you shouldn't use global in this context.
If you want to set your ORM model in the before function, just make a variable in your controller and add it like this.
public function before()
{
$this->orm_group = ORM::factory('type');
}
In your Model your should also add the functions to access data and keep the controllers as small as possible. You ORM model could look something like this.
public class Model_Group extends ORM {
//All your other code
public function get_by_type($type)
{
return $this->where('type', '=', $type)->find_all();
}
}
Than in your controllers you can do something like this.
public function action_index()
{
$type = $this->request->param('type');
$result = $this->orm_group->get_by_type($type);
}
I hope this helps.
I always create an helper class for stuff like this
Class Grouphelper{
public static function getGroupByType($type){
return ORM::factory('Group')->where('type','=',$type)->find_all();
}
}
Now you're been able to get the groups by type where you want:
Grouphelper::getGroupByType($type);
Looking for some guidance in designing my new MVC 4 app.
I would like to have a url parameter s=2011 on every page of the app to let me know what year of data I'm working with. Obviously, the user will have a way to change that parameter as needed.
I will need that parameter in every controller and wondering the best way to do this. I was thinking of creating a base controller that reads Request.QueryString and puts the year into a public property. However, considering all the extensability points in MVC, I'm wondering if there's a better way to do this?
This very much depends on the design of your app, but just to give you two alternatives
IActionFilter
If you are doing data context per request you can use a global IActionFilter to hook pre-action execution globally and apply a query filter to your data context behind the scenes.
Major down-side of this is that to test the controller you will need to have the full MVC pipeline setup so that the actionfilter gets applied properly.
Dependency Injection
Instead of using sub-classing (base controller as you say) you can use dependency injection . Keeping things more loose will allow you to pull the filter from query string, cookie, user setting in the database or whatever else - without your controller knowing where it comes from.
Here is some pseudo code how I would do it if I was using something like Entity Framework or Nhibernate (also I am sure applicable with other technologies as well)
public Car
{
public string Year { get; set; }
}
public class CarsDataContext : DbContext
{
private IQuerable<Cars> _cars = null;
private Func<Car, bool> _carsFilter = null;
public IQuerable<Car> Cars {
get {
if (_carsFitler != null)
return _cars.Where(_carsFitler);
return _cars;
}
set { _cars = value; }
}
public void ApplyCarsFilter(Func<Car, bool> predicate)
{
_carsFilter = predicate;
}
}
Assuming you have dependency injection setup already (NInject or whichever other framework) in you can configure how the context to be intialized
Bind<CarsDataContext>().ToMethod(() => {
string yearFilter = GetYearFilter(); // can be coming from anywhere
CarsDataContext dataContext = new CarsDataContext();
dataContext.Applyfilter(car => car.Year == yearFilter);
return dataContext;
}).InRequestScope();
Then my controller knows nothing about the data filtering and I can easily test it:
class MyController : Controller
{
public MyController(CarsDataContext dataContext)
{
}
...
}
However I would only do this is filtering the dataset was across many controllers and important part of my software. Otherwise it's pure over-engineering.