kundera
kundera copied to clipboard
Redis: Relation values are not deleted in case of one to many associations
Suppose Person==>Address is holding up 1-M relation. while doing:
em.delete(person) or executing "Delete from Person p"; cascade deletion is working fine, but it is not deleting PERSON_ID column value held by Address table/column family.
-Vivek
+1
Just to add, This is specific to Redis only. Working fine for other databases.
-Vivek
I would suggest the creation and usage of more labels for tagging issues (such as one per each supported engine, bug, improvement, documentation, etc.). This would help to better organize and prioritize issues.
Yeps. Makes sense, modified.
-Vivek
You changed the name, but could use Github labels ;-) if you need help triaging issues, I'd be willing to help but only have some experience in Cassandra (as you might have figured by now).
looks like redis one - to - many still doesn't work. As well as many-to-many. I've checked out kundera-3.6 and ran com.impetus.client.RedisAssociationTestMTM - it fails with assertions. This makes impossible to use relations with redis.
Is there anything I'm missing about this?
Hi @alunev,
com.impetus.client.RedisAssociationTestMTM
test case should not fail. Please share exact error.
-Dev
Hi, @devender-yadav ,
thanks a lot for response. I've revised the code and the test now works with some corrections. However, there's still a problem with cascade remove. Here are the details.
- checked out kundera-3.7
- run com.impetus.client.RedisAssociationTestMTM#testCrud, get NPE:
java.lang.NullPointerException
at com.impetus.client.RedisAssociationTestMTM.getNewEM(RedisAssociationTestMTM.java:349)
at com.impetus.client.RedisAssociationTestMTM.setUp(RedisAssociationTestMTM.java:50)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
- pretty obvious to fix though(I guess the intention was to delete records, if any, and re-create EM):
@Before
public void setUp() throws Exception
{
emf = Persistence.createEntityManagerFactory("redis_pu");
em = getNewEM();
// Delete by query.
Query query = em.createQuery("Delete from PersonMTMRedis p");
query.executeUpdate();
}
private EntityManager getNewEM()
{
if (em != null && em.isOpen())
{
em.close();
}
return em = emf.createEntityManager();
}
- after fix, I run it again against local redis and it passed
- however, there appears to be a problem: testCrud() deletes both persons in the end, so I expect DB to be empty, but it's not:
127.0.0.1:6379> keys *
1) "AddressMTM:ADDRESS_ID:109.0"
2) "AddressMTM:ADDRESS_ID:145.0"
3) "AddressMTM:ADDRESS_ID:101.0"
4) "PERSONMTM:PERSON_ID:2"
5) "PERSONMTM:PERSON_ID:1"
Furthermore, I was able to reproduce the original problem which led me to this test. Here's the test method:
@Test
public void removeCascade() throws Exception {
AddressMTMRedis address1 = getAddress(101.0, "NCR");
PersonMTMRedis person1 = getPerson("1", "User1", 20, Sets.newHashSet(address1));
em.persist(person1);
em = getNewEM();
PersonMTMRedis resultPerson = em.find(PersonMTMRedis.class, "1");
assertNotNull(resultPerson);
em = getNewEM();
resultPerson = em.find(PersonMTMRedis.class, "1");
em.remove(resultPerson);
em = getNewEM();
resultPerson = em.find(PersonMTMRedis.class, "1");
assertNull(resultPerson);
em = getNewEM();
AddressMTMRedis addr = em.find(AddressMTMRedis.class, 101.0);
assertNull(addr);
}
It gives assertion error on the last line:
junit.framework.AssertionFailedError: Expected: <null> but was: com.impetus.client.entities.AddressMTMRedis@272113c4
Expected :<null>
Actual :com.impetus.client.entities.AddressMTMRedis@272113c4
<Click to see difference>
at junit.framework.Assert.fail(Assert.java:47)
at junit.framework.Assert.assertTrue(Assert.java:20)
at junit.framework.Assert.assertNull(Assert.java:233)
at junit.framework.Assert.assertNull(Assert.java:226)
at com.impetus.client.RedisAssociationTestMTM.removeCascade(RedisAssociationTestMTM.java:238)
and the DB contents:
127.0.0.1:6379> keys *
1) "AddressMTM:ADDRESS_ID:101.0"
2) "ADDRESS_ID:1"
3) "AddressMTM:101.0"
4) "PERSONMTM:PERSON_ID:1"
5) "ADDRESS_ID:1_101.0"
6) "ADDRESS_ID:101.0"
7) "AddressMTM:ADDRESS_ID"
Looks like Person object was removed, but the associated address and all the relation tables - not.
I think the following 2 points are important here:
- the em is closed and re-created between remove and find. This ensures that we re-read object from db.
- the update made is not field value change, but rather deletion of the whole object
Please let me know if I'm missing something here or is this a bug.
Hi @alunev,
Thanks a lot for extensive testing.
From Kundera's testcase - remaining data
1) "AddressMTM:ADDRESS_ID:109.0"
2) "AddressMTM:ADDRESS_ID:145.0"
3) "AddressMTM:ADDRESS_ID:101.0"
4) "PERSONMTM:PERSON_ID:2"
5) "PERSONMTM:PERSON_ID:1"
is basically indexes.
From your case - Address object is still there. We are able to reproduce this at our end. This is due to LAZY fetching of addresses in person object. This is a bug and we will fix it in future release. A quick workaround would be changing FetchType of address to EAGER.
If you are want to contribute to Kundera, we are here to help!
-Dev
@devender-yadav thanks yet again for quick response. Yes, the above test passes with fetch = EAGER. However, the following, slightly modified one - still doesn't(here I try to delete one of the Addresses in Person instead of Person itself):
@Test
public void removeOneOfRelatedObjects() throws Exception {
AddressMTMRedis address1 = getAddress(101.0, "NCR");
AddressMTMRedis address2 = getAddress(102.0, "NCR");
PersonMTMRedis person1 = getPerson("1", "User1", 20,
Sets.newHashSet(address1, address2)
);
em.persist(person1);
em = getNewEM();
PersonMTMRedis resultPerson = em.find(PersonMTMRedis.class, "1");
assertNotNull(resultPerson);
em = getNewEM();
resultPerson = em.find(PersonMTMRedis.class, "1");
resultPerson.getAddress().remove(address2);
em.persist(resultPerson);
em = getNewEM();
resultPerson = em.find(PersonMTMRedis.class, "1");
assertEquals(1, resultPerson.getAddress().size());
em = getNewEM();
AddressMTMRedis addr = em.find(AddressMTMRedis.class, 102.0);
assertNull(addr);
}
Hi @alunev,
I am able to replicate this issue at my end. We will look into this issue. Thank you for pointing out.
-Dev