Spring Sort by Value with Page - spring

There are about 100 product objects in the database. Users upload products to the system.
I want to show these products on the homepage, I want to show which product it is.
First, i wanted to do this with List. But in order not to tire the database, i wanted to use Page. But, I couldn't figure out how can i sort there records.
This is my Service:
public Page<Market> getMarketItemsByPage(Pageable page,String pName) {
Page<Market> allProductsSortedByName = marketRepository.findAllByProductName(pName,page);
return allProductsSortedByName;
}
This is my repository:
#Repository
public interface MarketRepository extends JpaRepository<Market, Long> {
Page<Market> findAllByProductName(String pName ,Pageable pageable);
List<Market> findByUserId(Long id);
}
I want to show the last 10 products added on the page. I can do this with List easily, but according to my research, if i use page, the app is less tired.

You've to create Pageable with Sort like below:
Pageable pageable = PageRequest.of(page,size, Sort.by("pName").descending());

Related

Spring Pagination sorting with cases

I have a problem with Sorting in Spring. I have an enum class
public enum Category {
A,
B,
C,
D,
E,
F;
private static final List<Category> THRILLER;
static {
THRILLER = Arrays.asList(A, F, D);
}
private static final List<Category> DRAMA;
static {
DRAMA = Arrays.asList(C, E, B);
}
}
The Movie Entity:
#Entity
#Table
public class Movie {
...
private Category category;
private Timestamp realizationDate;
....
}
Now I have a rest endpoint that return movies List. I want to Sort this list according to the following order: Movies they belong to THRILLER should be displayed first. When two movies belong to the same category then this should be sorted by realization date.
#GetMapping(value = "/movies")
public ResponseEntity<PagedResources<Movie>> list(#PageableDefault() Pageable pageable) {
.......
}
I tried it with:
#SortDefault.SortDefaults({SortDefault(sort="category", direction=Sort.Direction.ASC), SortDefault(sort="realizationDate", direction=Sort.Direction.ASC)})
But this Sort the enum only alphabetically.
I need a possibility to do something like: Sort.by(Category.THRILLER.contains(movie.getCategory())). It is possible that I achieve that with Pageable or should I do it another way?
Spring Data directly only supports sorting by simple attributes.
So in order for this to work you need to provide an isThriller attribute.
You can do this with the existing object structure by using:
a) a trigger to fill the column in the database
b) use a view to compute the desired value
c) if you use Hibernate you may use the #Formula annotation to instruct it to compute the value.
In either case you are hardcoding the categories that make up thrillers in a String or in the database.
If you don't want that you could make Category an entity with an isThriller attribute which you then can query and sort by in the usual fashion.
AFAIK Sort in spring pagination sorts fields only in lexicographical order (same like in SQL, uneless you use some procedural version of SQL like PSQL) so you can't introduce some custom logic of sort.
You have two options:
introduce custom procedure/function into your DB and call it from code (ugly & bad approach)
Sort list of movies by playing with lambdas and custom comparators, after fetching it from DB (clean & simpler approach)

Spring Data JPA and Spring Web Updating Entities Avoiding Associations

I have the following entities:
Area
Listing
They are both many-to-many:
An area can have many listings
A listing can have many areas
Both Area and Listing have other fields like name, domain, etc.
I'm using Spring Web RestController as a way to update the entities.
For example:
#PutMapping("/{id}")
public Area update(#PathVariable Long id, #RequestBody Area update) {
return areaRepository.save(update);
}
However, as an Area can have many thousands of Listings, it's not practical to pass them all in the update request when I just want to update the Area name and other basic fields in my web application.
For example, the update json in the http request would be:
{
"id" : 69,
"name" : "San Francisco",
"domain" : "foo",
...
}
When serialised, the area instance above will have a listings field equal to null (obviously) and then when saved, all association are remove from this Area.
I'm thinking that I could do a select-then-update set of operations and only update the values necessary but that is cumbersome - especially when there are many dozens of non-association fields.
The question would be: how can I try to keep to the above code and http request and not remove all of the existing Listing associations when saving the input area? Is this possible? I want to update the name and other basic fields but not the association fields.
You can use the BeanUtilBean(org.apache.commons.beanutils.BeanUtilsBean).
Step 1: Create custom beanutilbean class.
#Component
public class CustomBeanUtilsBean extends BeanUtilsBean {
#Override
public void copyProperty(Object dest, String name, Object value)
throws IllegalAccessException, InvocationTargetException {
if(value==null)return;
super.copyProperty(dest, name, value);
}
}
Step 2: In your controller while updating. first get the Area from database & use copyProperties method as shown in below.
#PutMapping("/{id}")
public Area update(#PathVariable Long id, #RequestBody Area update) {
Area areaDB = areaRepository.findOne(update.getId());
customBeanUtilsBean.copyProperties(areaDB,update);//it will set not null field values of update to areaDB.
return areaRepository.save(areaDB);
}
Hope this will helps you..:)
Since you are using spring-data-jpa repository you can write a new method that takes the changed values of Area object with #Modifying and #Query annotations on it.
In the #Query you specify the HQL query with update statement as in here

Can I require a one-to-one relationship in Laravel Eloquent?

I've got a Product class and a Detail class. I wanted to separate the big, long description from the basic data (sku, price) just for speed. However there will always be a big long description. So each item in the store will always have two records.
Is there a way to force or require both records? Is there a way to require that the 1-to-1 relationship exists - so that this would always work...
$P = new App\Product(['sku'=>'123','price'=>69]);
$P->Detail->html = '<p>Lorem ipsum.</p>';
$P->push();
My hasOne/belongsTo stuff is all fine. But if the details record does not exist yet ~ I get errors. I'm wondering if Detail can auto-magically exist.
There's not a lot you can do to 'force' the paired record to exist, however you could use a getter to make the retrieval of the description a little safer. Something like:
class Product extends Model {
public function detail()
{
return $this->hasOne('App\Detail');
}
public function getDetailHtml()
{
if ($this->detail()->count()) {
return $this->detail->html;
}
}
}

How to use a Dictionary or Hashtable for LINQ query performance underneath an OData service

I am very new to OData (only started on it yesterday) so please excuse me if this question is too dumb :-)
I have built a test project as a Proof of Concept for migrating our current web services to OData. For this test project, I am using Reflection Providers to expose POCO classes via OData. These POCO classes come from in-memory cache. Below is the code so far:
public class DataSource
{
public IQueryable<Category> CategoryList
{
get
{
List<Category> categoryList = GetCategoryListFromCache();
return categoryList.AsQueryable();
}
}
// below method is only required to allow navigation
// from Category to Product via OData urls
// eg: OData.svc/CategoryList(1)/ProductList(2) and so on
public IQueryable<Category> ProductList
{
get
{
return null;
}
}
}
[DataServiceKeyAttribute("CategoryId")]
public class Category
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public List<Product> ProductList { get; set; }
}
[DataServiceKeyAttribute("ProductId")]
public class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
}
To the best of my knowledge, OData is going to use LINQ behind the scenes to query these in-memory objects, ie: List in this case if somebody navigates to OData.svc/CategoryList(1)/ProductList(2) and so on.
Here is the problem though: In the real world scenario, I am looking at over 18 million records inside the cache representing over 24 different entities.
The current production web services make very good use of .NET Dictionary and Hashtable collections to ensure very fast look ups and to avoid a lot of looping. So to get to a Product having ProductID 2 under Category having CategoryID 1, the current web services just do 2 look ups, ie: first one to locate the Category and the second one to locate the Product inside the Category. Something like a btree.
I wanted to know how could I follow a similar architecture with OData where I could tell OData and LINQ to use Dictionary or Hashtables for locating records rather than looping over a Generic List?
Is it possible using Reflection Providers or I am left with no other choice but to write my custom provider for OData?
Thanks in advance.
You will need to process expression trees, so you will need at least partial IQueryable implementation over the underlying LINQ to Objects. For this you don't need a full blown custom provider though, just return you IQueryable from the propties on the context class.
In that IQueryable you would have to recognize filters on the "key" properties (.Where(p => p.ProductID = 2)) and translate that into a dictionary/hashtable lookup. Then you can use LINQ to objects to process the rest of the query.
But if the client issues a query with filter which doesn't touch the key property, it will end up doing a full scan. Although, your custom IQueryable could detect that and fail such query if you choose so.

MVC2/LINQ Repository pattern help for a beginner

I have the following method in my repository that returns a mix of two objects from my database,
public IQueryable <ICustomersAndSitesM> CustomerAndSites
{
get
{
return from customer in customerTable
join site in customerSitesTable
on customer.Id equals site.CustomerId
select new CustomersAndSitesMix(customer, site);
}
}
This is my interface code for the ICustomerAndSitesM
interface ICustomersAndSitesM
{
IQueryable<Customer> Customers { get; }
IQueryable<CustomerSite> CustomerSites { get; }
}
Im struggling with working out how and where to define CustomersAndSitesMix, should this be a seperate class or a method in the interface? and will that need to have definttions for both the customer and customer site?
I would set CustomersAndSitesMix up as a class with all the properties from your other two tables that you need. I am not sure why you are needing this interface, but I would also change the return type of your method to List<CustomersAndSitesMix> and add a ToList() on the end of your LINQ query. Then you would return an inner join of both tables, which may be what you want or you may want to add an arguement, say CustomerID to your function so you could pass it in and get only a subset.

Resources