javax.persistence.cache.retrieveMode and javax.persistence.cache.retrieveMode does not work with NamedQuery when used with Eclipse Link ORM - jpa

Query Hints not working in Eclipse Link 2.3.2/2.6.1 when used to fetch data from second level Cache
Used Hints,
#QueryHint(name = "javax.persistence.cache.retrieveMode", value = "USE"),
#QueryHint(name = "javax.persistence.cache.storeMode ", value = "USE")
Tried with below options.
1. Added JPA Hints to Named query itself
#NamedQuery(
name = TestEntity.FIND_BY_CODE,
query = "select t from Test t where t.code = :code",
hints = {
#QueryHint(name = "javax.persistence.cache.retrieveMode", value = "USE"),
#QueryHint(name = "javax.persistence.cache.storeMode ", value = "USE") })
2. Adding hints to the Entity Manager Itself after injecting it
em.setProperty("javax.persistence.cache.retrieveMode", CacheRetrieveMode.USE);
em.setProperty("javax.persistence.cache.storeMode", CacheRetrieveMode.USE);
3. Added JPA hints at the time of Query execution
em.createNamedQuery(TestEntity.FIND_BY_CODE,
AlertCategoryType.class).setHint("javax.persistence.cache.retrieveMode", CacheRetrieveMode.USE)
.setHint("javax.persistence.cache.storeMode", CacheStoreMode.USE)
.setParameter("code", code).getSingleResult();
None of the above usage of hints worked. Then i tried debugging on three different options what i found is,
the Data Base Query which formed after setting these hints is passing hints as key/value pair below.
eclipselink.query.hints => {javax.persistence.cache.retrieveMode=USE, javax.persistence.cache.storeMode=USE}
Where eclipselink.query.hints is the key even when we have set the JPA hints. This is something we don't have control over to change this.
But when i pass Eclipse Link provided hints as below , It started working as expected and the Results are fetched from Cache and not from the DB.
eclipselink.query.hints => {eclipselink.query-results-cache.size=500, eclipselink.query-results-cache=true}
It means That When we use Eclipse Link it only recognizes Eclipse Link provided hints according to the key[ above shown] we see in Query.
Please suggest any work around to get the JPA Hints working
Environment I'm using is
Eclispe Link 2.3.2/2.6.1
Runnin fin serve Glassfish 4.1[payara]
Java8/JEE7

The query hint you state is working (eclipselink.query-results-cache) is completely unrelated - it creates a new cache for the query results so that next time you execute that same query, the results are already there, so it does not need to execute the query again. This is outside (above an beyond) the second level cache.
The settings you refer to as not working affect the second level cache. Without more information, I'm going to state they are likely working as expected. Just because your query goes to the database does not mean the cache isn't being used. Caching entities is very different than caching the results to a query. If the query results are not cached, unless you have in-memory querying enabled, most read-all type queries must go to the database to determine what entities need to be built and returned. EclipseLink will then use those results to check the cache- if the entities already exist, they are returned as is - this avoids the overhead of rebuilding entities from the data.
You can check if your entity has been cached by using a em.find() or read query that uses the ID value. The cache is indexed by ID, so it will not need to go to the database to figure out which entities you want.

Related

Getting translated records in CommandController

I've searched and debugged the last couple of days how to obtain the
translated version of a DomainModel object in a CommandController in Typo3 v8.7.
In Typo3 4.5/4.7 I've done the following:
- input: DomainModel in default language
- build a query that finds the record with the l10n_parent matching the
given domain model
- obtain a new domain model with the desired sys_language_uid
Unfortunately this does not work in Typo3 v8.7 any more. I always get
the domain model for the default language.
I've traced this down to the method Typo3DbBackend::doLanguageAndWorkspaceOverlay
called via Typo3DbBackend::getObjectDataByQuery
The query returns the correct (translated) row (seen in the debugger and also the mysql query log), but then the variable
$row gets overwritten in doLanguageAndWorkspaceOverlay no matter how I
set the querySettings setLanguageOverlayMode and setLanguageMode.
So what is the correct way to get a translated domain model in a
CommandController?
UPDATE:
I think I'm a step further. If I add ->setQueryLanguage(1) to the query settings, doLanguageAndWorkspaceOverlay() tries to fetch the translated record for language = 1. But in order to succeed I need to trick the FrontendGroupRestriction class by setting $GLOBALS['TSFE']->gr_list = "0,-2";.
The array returned by doLanguageAndWorkspaceOverlay() now contains all translated entries, except the uid, which is still the uid from the record in the main language. The uid of the translated record is stored in _LOCALIZED_UID.
Now my problem now is that I still get the record in the main laguage because DataMapper->mapSingleRow() (called via DataMapper->map()) has some kind of object cache and thus returns the object in the default language (because the uid is still the one of the record in the main language).
All this seems a little hackish. So again my question: what is the correct way to get a translated domain model in a CommandController?
thanks,
mika
p.s.: I've set up the second language in the backend and creating a translated record works just fine. My question is just how to I get an existing translated record in a CommandController.
alternative solution:
based on the solution above, I decided that I can do almost everything
on my own. So what I do now is
i) create an independend querybuilder for the according table:
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($tableName);`
ii) select the record with the desired l10n_parent and sys_language_uid
$query = $queryBuilder->select('*')
->from($tableName)
->where($queryBuilder->expr()->eq('sys_language_uid', $langId))
->andWhere($queryBuilder->expr()->eq('l10n_parent', $parentUid))
->execute();
iii) fetch all records into an array
$rows = $query->fetchAll();
iv) invoke the DataMapper manually to get the object
$dataMapper = $this->objectManager->get(DataMapper::class);
$translated = $dataMapper->map($className, $rows);
I know it has nothing to do with the ModelRepository any more, but it
works quite fine for now...
that's all folks
My solution to the issue described above:
To avoid invoking the DataMapper as part of the query from
Typo3DbBackend, I used a raw query (argument for ->execute()) and get
back an array, that already went through language overlay etc.
BUT: in
the array the '_LOCALIZED_UID' is still available. So I overwrite the
uid with the value from '_LOCALIZED_UID' and invoke the DataMapper
manually. Quite cumbersome and very hackish to overcome the Typo3
backend shortcomings...

TYPO3 7.6 Backend module to list values from several tables

I have been struggling for some time now and I can't really find anyone having done the same thing before.
I'm creating a backend module in TYPO3 7.6 which belongs to a shop extension.
The shop extension with the backend module was created with the extension builder. The shop has the following three models:
Product (products which can be ordered through the shop)
Productsorder (link to the customer)
ProductsorderPosition (the ordered product, the ordered amount and size and the link to the Productsorder)
The customers are of a model type from a different extension. These customers are linked to fe_users.
Now what I wanna do in my backend module is getting an overview to all these orders listed with the customer, some information about the fe_user and of course the product. I have created a sql-query, which does exactly that:
SELECT p.productname, p.productpriceperpiece,
pop.amount, pop.size,
h.name, h.address, h.zipcode, h.city, h.email, h.phone,
f.first_name, f.last_name, f.email
FROM `tx_gipdshop_domain_model_productorderposition` AS pop
JOIN `tx_gipdshop_domain_model_product` AS p ON pop.products = p.uid
JOIN `tx_gipdshop_domain_model_productsorder` AS po ON pop.productorder = po.uid
JOIN `tx_gipleasedisturbhotels_domain_model_hotel` AS h ON po.hotel = h.uid
JOIN `fe_users` AS f ON h.feuser = f.uid
If I use this query from the product repository it gives back the right amount of data records but they're of type product and the products are all "empty" (uid = 0 etc).
I've added an additional action for this in the product controller (getOrdersAction) and in the repository containing the query I've added a method findAllOrders.
I'm still rather a beginner in TYPO3 but I can somehow understand why it returns data sets of type Product when the query is called from the ProductRepository. But what I do not know is how I can get all the information from the query above and list it in the backend module.
I've already thought about moving the query to the ProductsorderPositionRepository but I would probably be faced with a similar problem, it would only return the information from the ProductsorderPosition and everything else would be left out.
Can someone point me to the right direction?
Would I need to create another model with separate repository and controller? Isn't there an easier way?
If you need more information, just ask! ;)
First of all, you are doing a joined query with subsets of data mixed from multiple tables. There is nothing against this.
Because of this, there is no "model" which has the mixed datasets.
If you are using the default query thing in a repository, the magic behind the repository assumes that the result of the query statement reflects the defined base model for this repository.
Moving the query function to another repository does not solve the problem.
You have not provided the code snippet you are executing the sql statement, so I assume you have used the query thing in the repository to execute the statement. Something like this:
$result = $query->statement('
SELECT p.productname, p.productpriceperpiece,
pop.amount, pop.size,
h.name, h.address, h.zipcode, h.city, h.email, h.phone,
f.first_name, f.last_name, f.email
FROM `tx_gipdshop_domain_model_productorderposition` AS pop
JOIN `tx_gipdshop_domain_model_product` AS p ON pop.products = p.uid
JOIN `tx_gipdshop_domain_model_productsorder` AS po ON pop.productorder = po.uid
JOIN `tx_gipleasedisturbhotels_domain_model_hotel` AS h ON po.hotel = h.uid
JOIN `fe_users` AS f ON h.feuser = f.uid', NULL);
or have used the query building stuff.
First solution
The first and simpliest solution would be to retrieve the result as plain php array. Before TYPO3 7.0 you could have done this by using this:
$query->getQuerySettings()->setReturnRawQueryResult(TRUE);
With TYPO3 7.0 this deprecated method was removed from the core.
The only way is to define the query and call $query->execute(TRUE); for now.
This should return the data in pure array form.
This is the simpliest one, but as we are in the extbase context this should not be suffering enough.
Second Solution - no, just an idea that I would try next
The second solution means that you have some work to do and is for now only a suggestion, because I have not tried this by myself.
Create a model with the properties and getter/setters for the result columns of your query
Create a corresponding repository
Third solution
Not nice, but if nothing else works, fall back to the old TYPO3 v4 query methods:
$GLOBALS['TYPO3_DB']->exec_SELECTgetRows([...]))
and replace this with the QueryBuilder in/for TYPO3 v8.
This is really not nice.
I hope I could direct you to the right way, even if not giving a full solving solution.

SQL Update Record Failed because derived or constant field

I'm very new to SQL statements to update / manage records.
I have a very simple request and I have look into it online but it doesnt fully make sense as I am new.
My query is
Update [Data].[viewAppFieldList]
Set level = 308
Where fieldid = 23456
When I run it of course I get the error that it failed because it contains a derived or constant field.
Can someone explain why it is doing that, my assumption is because it is applicable in more than one place.
Secondly how do I go about manipulating it so this can be changed?
Thank you!

Entity Framework and Identity Insert

I am writing an application that exports data and serializes it to file for archiving old data.
There may be occasions where for some reason select data needs to be re-imported. This has been causing me a problem because of an identity column.
To get around this I am performing the work inside a transaction scope. Setting the Identity Insert On for that table and then updating my transaction e.g.
using (TR.TransactionScope scope = new TR.TransactionScope(TR.TransactionScopeOption.RequiresNew))
{
// allow transaction nbr to be inserted instead of auto generated
int i = context.ExecuteStoreCommand("SET IDENTITY_INSERT dbo.Transactions ON");
try
{
// check if it already exists before restoring
var matches = context.Transactions.Where(tr => tr.transaction_nbr == t.transaction_nbr);
if (matches.Count() == 0)
{
Transaction original = t;
context.Transactions.AddObject(original);
context.SaveChanges();
restoreCount++;
But I receive an exception saying:
Explicit value must be specified for identity column in table either when IDENTITY_INSERT >is set to ON or when a replication user is inserting into a NOT FOR REPLICATION identity >column.
I am assuming the entity framework is trying to do some sort of block insert without specifying the columns. Is there anyway to do this in the entity framework.
The object is large and has a number of associated entities that are also deserialized and need inserting so I want to let the entity framework do this if possible as it will save me a lot of extra work.
Any help is appreciated.
Gert Arnold - that was the answer to my question. Thank you.
I did read that elsewhere and had set the value in the object browser so thought this was suffice. I also double checked the value by right clicking the .edmx and Open With to see the details in an XML editor as suggested in another post.
When I checked the value in the XML editor initially it too was "None" so assumed this wasn't my problem. But I guess just going in there and saving rectified the problem first time around.
The second time round after I must have updated the model from the database I had to repeat this step upon your suggestion. But the second time round the StoreGeneratorPattern was different to the one set in the object browser so I needed to manually change it in the XML.
In my circumstance this is fine since normally the records are inserted via another mechanism so the identity is just getting in the way for me as the identity will always be inserted as an old (used to exist) identity value which is being temporarily restored.
Thanks for your help.

Microsoft Access ADP UPDATE Query does NOT update

I have a (very simple and standard) UPDATE statement which works fine either directly in Query Analyser, or executed as a stored procedure in Query Analyser.
UPDATE A
SET
A.field1 = B.col1
, A.field2 = B.col2
FROM
tblA AS A INNER JOIN tblB AS B
ON A.pk1 = B.pk1 AND A.pk2 = B.pk2
Problem is when i execute the same stored proc via microsoft ADP (by double-clicking on the sproc name or using the Run option), it says "query ran successfully but did not return records" AND does NOT update the records when i inspect the tables directly.
Before anyone even says "syntax of MS-Access is different than SQLServer T-SQL", remember that with ADP everything happens on the server and one is actually passing thru to T-SQL.
Any bright ideas from any ADP gurus out there?
Gotcha. Responding to my own question for the benefit of anyone else.
Tools / Options / Advanced / Client-Server Settings / Default max records is set at 10,000 (presumably this is the default). Change this to 0 for unlimited.
My table had 100,000+ rows and whatever set of 10,000 it was updating was difficult to find ( among a sea of 90,000+ un-updated rows ). Hence the update did not work fully as expected.
Try and see whether the query gets executed on the SQL Server using SQL profiler.
Also, I think you might need to close the linked table & re-open it to see the updated records.
Does that work?
Run the query with SQL PRofiler running. Before you start the trace add in all the error events. This will give you any errors that the SQL Server is generating that the Access ADP might not be showing correctly (or at all).
Feel free to post them here.
Just as a reference, here's a paper I wrote on Update Queries that discusses some of the issues associated with when the fail.
http://www.fmsinc.com/microsoftaccess/query/snytax/update-query.html
I seem to remember that I always got the "didn't return any rows" message and had to simply turn off the messaging. It's because it isn't returning any rows!
as for the other - sometimes there's a primary key issue. Does the table being updated have a primary key in SQLServer? If so, check the view of the table in Access - sometimes that link doesn't come through. It's been a while, so I could be wrong, but I think you may need to look at the design view of the table while in access and add the primary key there.
EDIT: Additional thought:
in your debugging, try throwing in print statements to see what the values of your inputs are. Is it actually picking up the data from the table as you expect when you execute from access?