I have a specific query method in all my managers that must return a transient collection, but i want to CLOSE the query immediately after executing it.
tx.begin();
Query query=pm.newQuery(...);
Collection col=(Collection)query.execute();
pm.makeTransientAll(col,true);
query.close();
tx.commit();
The problem: The collection CANNOT be accessed after the query is closed (DN knows the identity?) otherwise it throws a "Query has been closed" error!
The solution: Create a COPY of the original collection!
Collection col=new ArrayList((Collection)query.execute());
But i want to avoid that... Even if it's a local copy and it's not a deep clone, it still allocates the space needed for the entire array of elements (so, at some point there is going to be 2x allocated memory) and i would like to avoid that.
I'm i missing something? Is there a way to avoid the creation of a clone?
Well, i found the reason of this behavior:
The query Object returned (collection) if an instance of: org.datanucleus.store.rdbms.query.ForwardQueryResult
that extends: AbstractRDBMSQueryResult
that extends: AbstractQueryResult
that extends: AbstractList
so, i get an object that is a LIST implementation, and the query result is bound to that implementation.
/** The Result Objects. */
protected List resultObjs = new ArrayList();
/**
* Method to return the results as an array.
* #return The array.
*/
public synchronized Object[] toArray()
{
assertIsOpen();
advanceToEndOfResultSet();
return resultObjs.toArray();
}
So, i cannot avoid the creation of a NEW array...
Related
I have a code in to get all data in one collection in cosmo db, if the collection is empty then start to inserting.
The first time the code is run collection is empty however, SetIterator.HasMoreResults return True, even though the collection is empty.
Then there will be error raising Microsoft.Azure.Cosmos.CosmosException : Response status code does not indicate success: NotFound, and I have checked with a collection that is not empty the code run fine.
I can use try catch to handle it, but it does not seems to be a nice solution, Does anyone know how to check if the collection is empty?
var itemList = new List<T>();
using (FeedIterator<T> setIterator = _container.GetItemLinqQueryable<T>()
.ToFeedIterator())
{
while (setIterator.HasMoreResults)
{
foreach (var item in await setIterator.ReadNextAsync())
{
itemList.Add(item);
}
}
}
return itemList;
You can use indexing to get empty collection in cosmos db. To do this you can use unique indexes. Unique indexes are created to only those which doesn’t contain any documents.
Important
Unique indexes can be created only when the collection is empty
(contains no documents).
To create unique indexes on collections you can go through unique indexes
During a PUT call to an item I need to get the current saved values in order to compare them to request params.
Say the PUT call contains a name parameter that is different from the currently saved one.
I thought getting the entity with $repository->findOneBy would return the saved value but it's not, I'm getting the PUT param value instead.
The setup is taken from https://api-platform.com/docs/core/events :
const ALLOWED_METHOD = Request::METHOD_PUT;
public static function getSubscribedEvents()
{
return [
KernelEvents::VIEW => [
['preWriteWorkflow', EventPriorities::PRE_WRITE],
],
];
}
public function preWriteWorkflow(GetResponseForControllerResultEvent $event)
{
$entity = $event->getControllerResult();
if (!($entity instanceof MyEntity)) {
return;
}
$route = "/{$entity->getId()}";
$result = $this->checkRequestFromControllerResult($event, $route);
if (!$result) {
return;
}
// Getting entity from repository in order to get the currently saved value
$savedEntity = $this->MyEntityRepository->findOneBy(['id' => $entity->getId()]);
// Both will return the Name value of the PUT call
// Shouldn't $savedEntity return the currently saved name ?
$entity->getName();
$savedEntity->getName();
}
What is the reason behind this behavior? Is there a way to get eventArgs injected in this method so that I can use getEntityChangeSet or hasChangedField?
What is the reason behind this behavior?
This is doctrine behaviour. Once you've fetched an entity, the instance is stored and always returned. Given that, you have one and only one instance of your entity during request's lifecycle.
$event->getControllerResult() === $repository->findBy($id); //true !
Roughly, Api-platform calls Doctrine and fetch your entity while executing the ReadListener. Because this is an object, doctrine's find*() methods always returns a pointer/reference to the entity, even if it is updated.
Yes, during a PUT request, the updated instance is the fetched one, in order to trigger doctrine update actions at the end of the request.
An easy way to keep an instance of the so called previous object is to clone it before the Deserialization event.
Note that this strategy is used by api-platform with the security_post_denormalize and previous_object security attributes.
EDIT
Working on a similar use case, i've found that the ReadListener stores the current object within the Request under the "data" key, whereas the previous object is stored within the "previous_data" key.
$entity = $request->get('data');
$previousEntity = $request->get('previous_data'); // This is a clone.
i want to delete record where company_id is "****" and gamer_id is "****".
How to write query for this .
public List<CompanyGamer> unfollowcompany(CompanyGamerForm CompanyGamerForm) throws NotFoundException {
String company_id = CompanyGamerForm.getCompany_id();
String gamer_id = CompanyGamerForm.getGamer_id();
Iterable<Key<CompanyGamer>> allKeys = ofy().load().type(CompanyGamer.class).filter("company_id=", company_id).filter("gamer_id=", gamer_id).keys();
ofy().delete().keys(allKeys); }
Please let me know what should be define in return ?
Have a look at the Objectify documentation for Queries https://github.com/objectify/objectify/wiki/Queries at the bottom of section "Executing Queries". "You can query for just keys, which will return Key objects much more efficiently than fetching whole objects"
Iterable<Key<Gamercompany>> allKeys = ofy().load().type(Gamercompany.class).filter("company_id=", compnyid).filter("gamer_id=",gamer_id).keys();
And then you can delete all entities corresponding to the keys:
ofy().delete().keys(allKeys);
Or if you do want to execute the query that returns the entities and not the keys, you could iterate over the Query and do:
ofy().delete().entity(thing); // asynchronous
or
ofy().delete().entity(thing).now(); // synchronous
However it would be less efficient than the first way.
I need help using fetch() in CloudCode on Parse.com
RIght now everything I do throws an error that says " Cannot create a pointer to an unsaved ParseObject".
I am starting to think that CloudCode is broken because it doesn't make sense at all because I'm not creating anything new or creating pointers.
It's simple as
query.find().then(function(lists){
lists.forEach(elem, i){
elem.get('owner').fetch({
success: function(user){
console.log(user);
}
})
}
});
Where 'owner' is a pointer to a user object and the query is on a class that contains a Pointer (owner) and an Array of objects. Essentially I want to get the email of the owner to compare to the Array of objects that also contain emails.
Trying to use include with the query also doesn't work.
In RavenDB I can store objects of type Products and Categories and they will automatically be located in different collections. This is fine.
But what if I have 2 logically completely different types of products but they use the same class? Or instead of 2 I could have a generic number of different types of products. Would it then be possible to tell Raven to split the product documents up in collections, lets say based on a string property available on the Product class?
Thankyou in advance.
EDIT:
I Have created and registered the following StoreListener that changes the collection for the documents to be stored on runtime. This results in the documents correctly being stored in different collections and thus making a nice, logically grouping of the documents.
public class DynamicCollectionDefinerStoreListener : IDocumentStoreListener
{
public bool BeforeStore(string key, object entityInstance, RavenJObject metadata)
{
var entity = entityInstance as EntityData;
if(entity == null)
throw new Exception("Cannot handle object of type " + EntityInstance.GetType());
metadata["Raven-Entity-Name"] = RavenJToken.FromObject(entity.TypeId);
return true;
}
public void AfterStore(string key, object entityInstance, RavenJObject metadata)
{
}
}
However, it seems I have to adjust my queries too in order to be able to get the objects back. My typical query of mine used to look like this:
session => session.Query<EntityData>().Where(e => e.TypeId == typeId)
With the 'typeId' being the name of the new raven collections (and the name of the entity type saved as a seperate field on the EntityData-object too).
How would I go about quering back my objects? I can't find the spot where I can define my collection at runtime prioring to executing my query.
Do I have to execute some raw lucene queries? Or can I maybe implement a query listener?
EDIT:
I found a way of storing, querying and deleting objects using dynamically defined collections, but I'm not sure this is the right way to do it:
Document store listener:
(I use the class defined above)
Method resolving index names:
private string GetIndexName(string typeId)
{
return "dynamic/" + typeId;
}
Store/Query/Delete:
// Storing
session.Store(entity);
// Query
var someResults = session.Query<EntityData>(GetIndexName(entity.TypeId)).Where(e => e.EntityId == entity.EntityId)
var someMoreResults = session.Advanced.LuceneQuery<EntityData>(GetIndexName(entityTypeId)).Where("TypeId:Colors AND Range.Basic.ColorCode:Yellow)
// Deleting
var loadedEntity = session.Query<EntityData>(GetIndexName(entity.TypeId)).Where(e =>
e.EntityId == entity.EntityId).SingleOrDefault();
if (loadedEntity != null)
{
session.Delete<EntityData>(loadedEntity);
}
I have the feeling its getting a little dirty, but is this the way to store/query/delete when specifying the collection names runtime? Or do I trap myself this way?
Stephan,
You can provide the logic for deciding on the collection name using:
store.Conventions.FindTypeTagName
This is handled statically, using the generic type.
If you want to make that decision at runtime, you can provide it using a DocumentStoreListner