iOS Stackmob SDK(2.0.0) (relationships) Bug - relationship

I have found a critical bug with relationships. I try to set relationship for my SMUserManagedObject after saving in the block "saveOnSuccess" and have a crash with a log:
* Terminating app due to uncaught exception 'SMExceptionIncompatibleObject', reason: 'No Attribute found for entity User which maps to the primary key on StackMob. The Attribute name should match one of the following formats: lowercasedEntityNameId or lowercasedEntityName_id. If the managed object subclass for User inherits from SMUserManagedObject, meaning it is intended to define user objects, you may return either of the above formats or whatever lowercase string with optional underscores matches the primary key field on StackMob.'
It's looks like:
NSManagedObjectContext *context = [[[SMClient defaultClient] coreDataStore] contextForCurrentThread];
User *user = [[User alloc] initNewUserInContext:context];
[user setUsername:#"username1"];
[context saveOnSuccess:^{
user.group = group; //an already created object <--- Have a crash
} onFailure:^{
}];
After this my "Group" schema is spoiled. Any attempts is failure.
If I try to set in any other place something like:
user.group = group; //Before using saveOnSuccess trick this line work perfectly!
I have a crash. Then I need to remove "Group" scheme at stackmob "Schema Configuration" for repair.
So, I can't create an user object with presetted relationship.

You can do one of two things...
Change your User class to inherit from SMUserManagedObject. See the SMUserManagedObject section in the Stackmob Core Data Guide.
Or in the User class define a selector that returns the name of the primary key field:
- (NSString *)primaryKeyField
{
return #"username";
}

I found a solution: in my AppDelegate line "SM_CACHE_ENABLED = YES" make the crash...

Related

Two arrayCollection. Only one is an ArrayCollection [duplicate]

since 2 weeks, we are having this problem while trying to flush new elements:
CRITICAL: Doctrine\ORM\ORMInvalidArgumentException:
A new entity was found through the relationship 'Comment#capture' that was not configured to cascade persist operations for entity
But the capture is already in the database, and we are getting it by a findOneBy, so if we cascade persist it, or persist it, we get a
Table constraint violation: duplicate entry.
The comments are created in a loop with differents captures, with a new, and all required field are set.
With all of the entities persisted and / or got by a findOne (and all valid), the flush still fails.
I'm on this issue since a while, so please help me
I had the same problem and it was the same EntityManager. I wanted to insert an object related ManyToOne. And I don't want a cascade persist.
Example :
$category = $em->find("Category", 10);
$product = new Product();
$product->setCategory($category)
$em->persist($product);
$em->flush();
This throws the same exception for me.
So the solution is :
$category = $em->find("Category", 10);
$product = new Product();
$product->setCategory($category)
$em->merge($product);
$em->flush();
In my case a too early call of
$this->entityManager->clear();
caused the problem. It also disappeared by only doing a clear on the recent object, like
$this->entityManager->clear($capture);
My answer is relevant for topic, but not very relevant for your particular case, so for those googling I post this, as the answers above did not help me.
In my case, I had the same error with batch-processing entities that had a relation and that relation was set to the very same entity.
WHAT I DID WRONG:
When I did $this->entityManager->clear(); while processing batch of entities I would get this error, because next batch of entities would point to the detached related entity.
WHAT WENT WRONG:
I did not know that $this->entityManager->clear(); works the same as $this->entityManager->detach($entity); only detaches ALL of the repositorie`s entities.
I thought that $this->entityManager->clear(); also detaches related entities.
WHAT I SHOULD HAVE DONE:
I should have iterated over entities and detach them one by one - that would not detach the related entity that the future entities pointed to.
I hope this helps someone.
First of all, you should take better care of your code, I see like 3 differents indentations in your entity and controller - this is hard to read, and do not fit the Symfony2 coding standards.
The code you show for your controller is not complete, we have no idea from where $this->activeCapture is coming. Inside you have a $people['capture'] which contains a Capture object I presume. This is very important.
If the Capture in $people['capture'] is persisted / fetched from another EntityManager than $this->entityManager (which, again, we do not know from where it come), Doctrine2 have no idea that the object is already persisted.
You should make sure to use the same instance of the Doctrine Entity Manager for all those operations (use spl_object_hash on the EM object to make sure they are the same instance).
You can also tell the EntityManager what to do with the Capture object.
// Refreshes the persistent state of an entity from the database
$this->entityManager->refresh($captureEntity);
// Or
// Merges the state of a detached entity into the
// persistence context of this EntityManager and returns the managed copy of the entity.
$captureEntity = $this->entityManager->merge($captureEntity);
If this does not help, you should provide more code.
The error:
'Comment#capture' that was not configured to cascade persist operations for entity
The problem:
/**
* #ORM\ManyToOne(targetEntity="Capture", inversedBy="comments")
* #ORM\JoinColumn(name="capture_id", referencedColumnName="id",nullable=true)
*/
protected $capture;
dont configured the cascade persist
try with this:
/**
* #ORM\ManyToOne(targetEntity="Capture", inversedBy="comments", cascade={"persist", "remove" })
* #ORM\JoinColumn(name="capture_id", referencedColumnName="id",nullable=true)
*/
protected $capture;
Refreshing the entity in question helped my case.
/* $item->getProduct() is already set */
/* Add these 3 lines anyway */
$id = $item->getProduct()->getId();
$reference = $this->getDoctrine()->getReference(Product::class, $id);
$item->setProduct($reference);
/* Original code as follows */
$quote->getItems()->add($item);
$this->getDoctrine()->persist($quote);
$this->getDoctrine()->flush();
Despite my $item already having a Product set elsewhere, I was still getting the error.
Turns out it was set via a different instance of EntityManager.
So this is a hack of sorts, by retrieving id of the existing product, and then retrieving a reference of it, and using setProduct to "refresh" the whatever connection. I later fixed it by ensuring I have and use only a single instance of EntityManager in my codebase.
I got this error too when tried to add new entity.
A new entity was found through the relationship 'Application\Entity\User#chats'
that was not configured to cascade persist operations for entity: ###.
To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or
configure cascade persist this association in the mapping for example #ManyToOne(..,cascade={"persist"}).
My case was that I tried to save entity, that shouldn't be saved. Entity relations was filled and tried to be saved (User has Chat in Many2Many, but Chat was a temporary entity), but there were some collisions.
So If I use cascade={"persist"} I get unwanted behaviour - trash entity is saved. My solution was to remove non-saving entity out of any saving entities:
// User entity code
public function removeFromChats(Chat $c = null){
if ($c and $this->chats->contains($c)) {
$this->chats->removeElement($c);
}
}
Saving code
/* some code witch $chat entity */
$chat->addUser($user);
// saving
$user->removeFromChats($chat);
$this->getEntityManager()->persist($user);
$this->getEntityManager()->flush();
I want to tell about my case as that might be helpful to somebody.
Given two entities: AdSet and AdSetPlacemnt. AdSet has the following property:
/**
* #ORM\OneToOne(targetEntity="AdSetPlacement", mappedBy="adSet", cascade={"persist"})
*
* #JMS\Expose
*/
protected $placement;
Then error appears when I try to delete some AdSet objects in a cycle after 1st iteration
foreach($adSetIds as $adSetId) {
/** #var AdSet $adSet */
$adSet = $this->adSetRepository->findOneBy(["id" => $adSetId]);
$this->em->remove($adSet);
$this->em->flush();
}
Error
A new entity was found through the relationship 'AppBundle\Entity\AdSetPlacement#adSet' that was not configured to cascade persist operations for entity: AppBundle\Entity\AdSet#00000000117d7c930000000054c81ae1. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example #ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the problem implement 'AppBundle\Entity\AdSet#__toString()' to get a clue.
Solution
The solution was to add "remove" to $placement cascade options to be:
cascade={"persist","remove"}. This guarantees that Placement also becomes detached. Entity manager will "forget" about Placement object thinking of it as "removed" once AdSet is removed.
Bad alternative
When trying to figure out what's going on I've seen a couple answers or recommendations to simply use entity manager's clear method to completely clear persistence context.
foreach($adSetIds as $adSetId) {
/** #var AdSet $adSet */
$adSet = $this->adSetRepository->findOneBy(["id" => $adSetId]);
$this->em->remove($adSet);
$this->em->flush();
$this->em->clear();
}
So that code also works, the issue gets solved but it's not always what you really wanna do. Indeed it's happens quite rarely that you actually need to clear entity manager.

How to remove value from GAE NDB Property (type BlobKeyProperty)

It might be the most dumb question and my apologies for the same but I am confused
I have the following entity:
class Profile(ndb.Model):
name = ndb.StringProperty()
identifier = ndb.StringProperty()
pic = ndb.BlobKeyProperty() # stores the key to the profile picture blob
I want to delete the "pic" property value of the above entity so that it should look as fresh as if "pic" was never assigned any value. I do not intend to delete the complete entity. Is the below approach correct:
qry = Profile.query(Profile.identifier==identifier)
result_record_list = qry.fetch()
if result_record_list:
result_record_list[0].pic.delete() # or result_record_list[0].pic = none # or undefined or null
I am deleting the actual blob referred by this blob key separately
assign None to it and put it back to the datastore.
result_record_list[0].pic = None
result_record_list[0].put()
The datastore is an OO schemaless databse. So you can add and remove properties from the the Kind (ndb.Model) without the need of a schema update.
If you also want to cleanup the entities look at this anwser from Guido

Why does db.Model.get_by_id() return None when no parent is specified?

I'm running the following code in the GAE interactive console (/_ah/admin/interactive), and I do not understand why get_by_id() returns None when the parent is not specified. The docs do not make this limitation clear and I can't think of a reason to enforce it.
import my_model
print my_model.all().fetch(1)[0].key().id() # Returns 33006, used later
print my_model.get_by_id(33006)
print my_model.get_by_id(my_model.all().fetch(1)[0].key().id())
parent = my_model.all().fetch(1)[0].parent()
print my_model.get_by_id(33006, parent=parent)
Output:
33006
None
None
<my_model object at 0x109a6a690>
db.Model definition and code showing object creation with ancestor:
class my_model(db.Model):
user_id = db.StringProperty(indexed=True)
email = db.StringProperty(indexed=True, default=None)
def create(parent):
obj = my_model(user_id='x', email='y', parent=parent)
obj.put()
The answer to your question is: because the same ID could be in another entity but with a different parent.
The IDs will be all different with the same parent or for all entities without a parent, but if there is an ancestor then your numerical IDs are not unique.

Python - read with key in App Engine

I have a python program in Google App Engine
When finding an object in the datastore when I have the key as a string, how can I do a direct read. Below is my code which is performing a loop, not good.....
class Opportunity(db.Model):
customer = db.ReferenceProperty(Customer,collection_name='opportunitys')
BNusername = db.StringProperty()
opportunity_no = db.StringProperty()
# etc etc etc.....
#BnPresets holds the object key as a string
opportunitys = Opportunity.all()
opportunitys.filter('BNusername =',BnPresets.myusername)
for oprec in opportunitys:
if str(oprec.key()) == BnPresets.recordkey:
opportunity = oprec
# I have the object here and can process etc etc
You can instantiate db.Key from string by passing it directly to the constructor:
opportunity_key = db.Key(BnPresets.recordkey)
Once you have that, simply db.get to obtain the entity identified by this key:
opportunity = db.get(opportunity_key)
I guess (by looking at the query you use) that you also want to verify the username of the object you got:
if opportunity.BNusername == BnPresets.myusername
process_opportunity(opportunity)
That should be pretty much it. The bottom line is that you should use the key first - as it uniquely identifies your entity - rather than querying for some other property and iterating through results.

How to get LDAP unboundid AttributeSyntax?

I'm trying to find out the unboundid AttributeSyntax type for a specific attribute name and it's simply not working.
Here's the example test code that I'm using to achieve this:
#Test
public void testLDAPSchema() {
try {
LDAPConnection connection = new LDAPConnection();
connection.connect("hessmain", 389);
connection.bind("CN=Administrator,CN=Users,DC=FISHBOWL,DC=NET", "password");
Schema s = connection.getSchema();
System.out.println(s.toString());
AttributeTypeDefinition atd = s.getAttributeType("directReports");
Set<AttributeTypeDefinition> oat = s.getOperationalAttributeTypes();
Set<AttributeSyntaxDefinition> l = s.getAttributeSyntaxes();
AttributeSyntaxDefinition asd1 = s.getAttributeSyntax(atd.getOID());
AttributeSyntaxDefinition asd2 = s.getAttributeSyntax(atd.getSyntaxOID());
AttributeSyntaxDefinition asd3 = s.getAttributeSyntax(atd.getBaseSyntaxOID());
connection.close();
} catch (Exception e) {
Assert.fail(e.getMessage());
}
}
From the above code, all the sets are empty. This also means that no matter which OID I pass to the schema getAttributeSyntax method that I will simply get a null return.
Is there any reason why I can't get the attribute syntaxes from an Active Directory server schema?
Thanks
I don't think that this is specific to the UnboundID LDAP SDK for Java. I'm not sure that Active Directory exposes this information over LDAP. When I perform a general LDAP search to retrieve schema information, I can see the attributeTypes and objectClasses attributes, but ldapSyntaxes isn't returned (and in fact ldapSyntaxes doesn't appear in the list of attribute types).
Similarly, none of the attribute type definitions includes a USAGE element, which is what is used to indicate that the attribute type is operational (e.g., "USAGE directoryOperation").
It may well be that Active Directory simply doesn't report this information at all. It could be that it provides some other non-standard way to get this information (e.g., a control or extended operation, or some other entry that can be retrieved), but if there is then I don't know about it.

Resources