Room relational query method with paging - android-room

In Room 2.4, there is a new feature called relational query method in DAO which you can write your custom query to select columns from 2 entities and Room can be able to aggregate into Map<TableA, List<TableB>> return type.
I have a fairly complicated query which do left join with nested queries to return a map of railway stations and their associated rail lines (many-to-many relationship). I tried to make a #Query method returns Flow<Map<RailStation, List<RailLine>>> and it can return the map that I want.
Now, I want to go one step further to make it returns paging 3's PagingSource. As the original type is a Map, so I think I should make the paging #Query method as PagingSource<Int, Map.Entry<RailStation, List<RailLine>>>. (Map.Entry should be the representative type of a single list item rather than Map as it represent the whole query result.) However, the Room annotation processor complainted about this line saying that it cannot handle this type:
[ksp] RailStationDao.kt:130: Not sure how to convert a Cursor to this method's return type (androidx.paging.PagingSource<java.lang.Integer, java.util.Map.Entry<RailStation, java.util.List<RailLine>>>).
So my question is: does the Room annotation processor and Paging 3 support for relational query method with paging 3? If not, is there any alternative way to archive the same goal? It seems like the #Relation annotation in Room can only support for simple table joining, but my case is I need to write nested query in the LEFT JOIN clause.

Related

Spring JPA paginated query with Join Fetch - Count Query gives fetch error

(Note: all code examples are extremely simple. I know there are other ways to do such simple queries. The problem I am demonstrating, however, is a bigger deal for more complex queries).
There is a known issue with Spring JPA Repositories and paginated queries that I'm really hoping there is a good solution for. In JPQL, it is possible to use JOIN FETCH to specify that I want to eagerly fetch a related entity, rather than doing it lazily. This avoids the N+1 problem, among other things. JOIN FETCH requires that the owner of the association is included in the select clause. Here is a very simple example of the type of query I'm talking about:
#Query("""
SELECT p
FROM Person p
JOIN FETCH p.address
""")
Page<Person> getPeopleAndAddresses(Pageable page);
The problem with this kind of query is the pagination piece. When returning a Page, Spring will do the query I wrote but then also do a count query to get the total possible records. Spring appears to take my query exactly as written, and just replace SELECT p with SELECT COUNT(p). Doing this means that the owner of the JOIN FETCH association is no longer present in the SELECT clause, which then results in the JPQL giving an error.
The only way I know how to resolve this is to construct the query with separate query and countQuery values, like this:
#Query(query = """
SELECT p
FROM Person p
JOIN FETCH p.address
""", countQuery = """
SELECT COUNT(p)
FROM Person p
""")
Page<Person> getPeopleAndAddresses(Pageable page);
This resolves the JPQL JOIN FETCH error, because the count query no longer contains a JOIN FETCH clause. However, for complex queries with sophisticated JOINs and WHERE clauses, this will lead to excessive code duplication as I will have to write all that logic in two places.
This seems like the kind of issue where there really should be a better solution available. I'm exploring various alternatives, including Specifications (mixed feelings), Blaze Persistence, and others. However, I'm wondering if there is some way in Spring itself to resolve this issue so that the first code example would work without an error?

Neo4j Spring OGM query for list of entities always return distinct

Lets say i have a graph:
A - follows -> B
A - follows -> C
Now, i have a query to get followers for both B and C (which should return me A 2 times).
MATCH (a)<-[:FOLLOWS]-(followers)
WHERE a.username IN ['B','C']
RETURN followers
If i make this query through Neo4J browser, i get 2 records: A node 2 times. This is correct.
If i make the same query through Spring Repository i get a list with only 1 object (A).
So, through Spring's repository any query for entities performs as if i add DISTINCT, so there is no difference between regular query and DISTINCT one.
If i query for some property of a node, i.e. A.username, i get a list with two duplicate strings (as intended).
Is this behaviour expected?
Why ?
Is there a way to query fo full entities with duplicates, the same
way that Cypher query works in Neo4J itself?
In general this behaviour is correct:
The A is always the same and gets mapped as one object. It won't make any sense to create the very same object twice.
I don't know from your question what the query should map to. But assuming it should create List<A> for this query it is correct.
Returning the a.username will not map to any entity but can only get collected in a projection / #QueryResult. This result has no concept of equality or similar and will always get created for any returned "row" from the response.

LINQ- Update, Select and Delete as single query

I have a datatable (say myNameDT) which has data like this
Expected result:
When sector is Price, if it has fund value and component OTHER THAN "Active Return Contribution, It should update the Fundvalue in respective sector of Component Active Return Contribution. same applied for Index Value. Note: After update it should delete the unnecessary rows.
The result should look like,
Need as LINQ only. I have tried something as naive LINQ developer which is not fruitful. Thank you
What you're looking for is not feasible in a single LINQ statement. This is imposed not by LINQ itself but by the concept of SQL that LINQ relies on to perform operations on data. One of the things LINQ does, it lets you chain operations on the same dataset by combining them in a single query, however SELECTs cannot be combined with UPDATEs or DELETEs.
Finally, if what you're looking for is only syntactic sugar - this is not possible. If you are looking for a way to organize a set of data operations in a single TRANSACTION, you may want to look at these questions that give a hint on how LINQ interprets transaction operations:
TransactionScope vs Transaction in LINQ to SQL
How to create a LINQ to SQL Transaction?

Elasticsearch indexed database table column structure

I have a question regarding the setup of my elasticsearch database index... I have created a table which I have rivered to index in elasticsearch. The table is built from a script that queries multiple tables to denormalize data making it easier to index by a unique id 1:1 ratio
An example of a set of fields I have is street, city, state, zip, which I can query on, but my question is , should I be keeping those fields individually indexed , or be concatenating them as one big field like address which contains all of the previous fields into one? Or be putting in the extra time to setup parent-child indexes?
The use case example is I have a customer with billing info coming from one direction, I want to query elasticsearch to see if that customer already exists, or at least return the closest result
I know this question is more conceptual than programming, I just can't find any information of best practices.
Concatenation
For the first part of your question: I wouldn't concatenate the different fields into a field containing all information. Having multiple fields gives you the advantage of calculating facets and aggregates on those fields, e.g. how many customers are from a specific city or have a specific zip. You can still use a match or multimatch query to query for information from different fields.
In addition to having the information in separate fields I would use multifields with an analyzed and not_analyzed part (fieldname.raw). This again allows for aggregates, facets and sorting.
http://www.elasticsearch.org/guide/en/elasticsearch/reference/0.90/mapping-multi-field-type.html
Think of 'New York': if you analyze it will be stored as ['New', 'York'] and you will not be able to see all People from 'New York'. What you'd see are all people from 'New' and 'York'.
_all field
There is a special _all field in elasticsearch which does the concatenation in the background. You don't have to do it yourself. It is possible to enable/disable it.
Parent Child relationship
Concerning the part whether to use nested objects or parent child relationship: I think that using a parent child relationship is more appropriate for your case. Nested objects are stored in a 'flattened' way, i.e. the information from the nested objects in arrays is stored as being part of one object. Consider the following example:
You have an order for a client:
client: 'Samuel Thomson'
orderline: 'Strong Thinkpad'
orderline: 'Light Macbook'
client: 'Jay Rizzi'
orderline: 'Strong Macbook'
Using nested objects if you search for clients who ordered 'Strong Macbook' you'd get both clients. This because 'Samuel Thomson' and his orders are stored altogether, i.e. ['Strong' 'Thinkpad' 'Light' 'Macbook'], there is no distinction between the two orderlines.
By using parent child documents, the orderlines for the same client are not mixed and preserve their identity.

LINQ Lambda Order in writing the query

I have the following query:
var query = db.Prog
.Where (a => a.Prog != "00000" && a.fn != "Koll")
.Select(a => new {a.Prog, a.MEfn})
.OrderByDescending(a => a.MEfn)
The query works fine but wondering if there are general rules on the order in which you write a Lambda linq query. Meaning, .Where comes before .Select, etc.
Can somebody enlighten me on the order in which LINQ needs to be written or best practices.
There isn't a best practice on the order in which you write a LINQ query, it will depend on if you want to do your filtering first, or your projection. For example in your case, you are projecting to an anonymous type which doesn't include the 'fn' property which your filter uses, so it wouldn't be available to use in a where clause if your select was first.
A better practice would be to give your properties less cryptic names. Also, 'fn' doesn't follow the PascalCase for property names, and if it's a field then it probably shouldn't be public.
Yours can be a good order.
Let's distinguish the case where db points to an SQL DB with a very good LINQ provider and the case db is an in-memory object. I guess it's the first.
In case you are using a LINQ to SQL provider, the statements are evaluated only when you materialize the query into an object, so the SQL optimizer (inside the DB) will take care of ordering of statements.
The vice versa occurs when your statements are run against in-memory collections or to materialized collections coming from LINQ to SQL. In that case they are executed sequentially, so you want to execute first those statements that reduce the number of results in the collection. Where is the best candidate!!!
The order that they should be in are completely dependent on the context of what you are doing. So if your OrderBy is simply formatting the data to be friendly to view, put it at the end after you have trimmed your collection, if your looking for the First value of a sorted collection then maybe you would need it before the collection is iterated to get the first.

Resources