Return-Path: X-Original-To: apmail-cayenne-dev-archive@www.apache.org Delivered-To: apmail-cayenne-dev-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 2425293CD for ; Wed, 19 Oct 2011 07:03:24 +0000 (UTC) Received: (qmail 50966 invoked by uid 500); 19 Oct 2011 07:03:24 -0000 Delivered-To: apmail-cayenne-dev-archive@cayenne.apache.org Received: (qmail 50851 invoked by uid 500); 19 Oct 2011 07:03:23 -0000 Mailing-List: contact dev-help@cayenne.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cayenne.apache.org Delivered-To: mailing list dev@cayenne.apache.org Received: (qmail 50841 invoked by uid 99); 19 Oct 2011 07:03:22 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 19 Oct 2011 07:03:22 +0000 X-ASF-Spam-Status: No, hits=-0.0 required=5.0 tests=SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (nike.apache.org: local policy) Received: from [208.78.103.231] (HELO vorsha.objectstyle.org) (208.78.103.231) by apache.org (qpsmtpd/0.29) with SMTP; Wed, 19 Oct 2011 07:03:13 +0000 Received: (qmail 16543 invoked from network); 19 Oct 2011 07:02:51 -0000 Received: from unknown (HELO ?192.168.1.95?) (194.158.197.10) by vorsha.objectstyle.org with SMTP; 19 Oct 2011 07:02:51 -0000 From: Andrus Adamchik Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: quoted-printable Subject: Exposed FK and redundant mappings Date: Wed, 19 Oct 2011 10:02:50 +0300 Message-Id: To: dev@cayenne.apache.org Mime-Version: 1.0 (Apple Message framework v1084) X-Mailer: Apple Mail (2.1084) X-Virus-Checked: Checked by ClamAV on apache.org Just coming of a few months (!) of low intensity debugging of a single = problem that looked as if Cayenne resets a non-null to-one relationship = to null. The FK would be not null in the DB, but all instances of a = given object across all DataContexts in a given app would return null = for that one relationship. Turned out this wasn't an obscure race = condition, but rather the following scenario: 1. Assume Artist and Painting with painting having to one relationship = called "artist", but also an ObjAttribute called "artistId" 2. For an existing Artist you may create a new painting, call = "setArtist", but don't set the "artistId" attribute explicitly.=20 3. Commit - that creates a valid record with non-null PAINTING.ARTIST_ID = in the db, but the object snapshot stored in DataRowStore suddenly has = NULL for "ARTIST_ID" key. 4. =46rom here all DataContexts that fault this painting from the shared = cache will have NULL "artist" relationship, even though it is not null = in the DB. The actual behavior during (3 - commit) I think is less deterministic = and depends on the relative order of traversal of entity properties in = the ClassDescriptor. So theoretically there may have been a reverse = situation when NULL was saved to the DB, but not-null value remained in = the snapshot. In any event it is extremely confusing. If we take a broader look at this problem, it is a case of redundant = mapping (something in the DB layer is mapped multiple times in the = object layer). There can be other cases with yet unknown sets of = problems (e.g. multiple ObjRelationships over the same DbRelationship; = flattened relationships, with a matching set of 1-step relationships; = etc).=20 We only have a single case where redundant mapping is handled correctly = and consistently - exposed PK (meaningful or not) . Even if the exposed = PK is generated by Cayenne, we have a mechanism to update object = property. So this is a case when we do it right, and don't compromise on = user choices of mapping scenarios. In case of exposed FK we have 2 options - (1) just add a Modeler = validation to discourage this type of mapping (quick and easy) and (2) = actually analyze the above and other possible scenarios when we need to = synchronize relationship and attribute and write code to do that. #2 can = be done as a post-commit pass over the objects to sync redundant = mappings... Just not clear which one of the redundant mappings should be = used to sync the others... Thoughts?=20=