Source Code Cross Referenced for SFieldReference.java in  » Database-ORM » SimpleORM » simpleorm » core » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database ORM » SimpleORM » simpleorm.core 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        package simpleorm.core;
002:
003:        import simpleorm.properties.*;
004:        import java.sql.ResultSet;
005:
006:        /*
007:         * Copyright (c) 2002 Southern Cross Software Queensland (SCSQ).  All rights
008:         * reserved.  See COPYRIGHT.txt included in this distribution.
009:         */
010:
011:        /**
012:         Represents a foreign key reference from one record to another. It's
013:         initializer also normally generates the implicit foreign key fields.<p>
014:        
015:         For example, assume that <code>Employee</code> has a
016:         <code>DEPT_ID</code> field that refers to
017:         <code>Department.DEPT_ID</code>.  The <code>Employee</code> record
018:         would normally be declared as follows:-<p>
019:        
020:         <xmp>
021:         public class Employee extends SRecordInstance...
022:         static final SFieldMeta DEPARTMENT =
023:         new SFieldReference(meta, Department.meta);
024:         </xmp>
025:        
026:         Internally the <code>DEPARTMENT</code> <i>Reference</i> generates one
027:         or more <i>Foreign Key</i> fields that correspond to each key fields
028:         in <code>Department</code>.  In the example above, an implicit
029:         <code>Employee.DEPT_ID</code> field would be created.  Note that if
030:         the key defintion of <code>Department</code> changed then this would
031:         be automatically propogated to the <code>Employee</code> record.<p>
032:        
033:         It is also possible to declare the foreign key fields explicitly,
034:         which enables extra parameters such as column names to be explicitly
035:         specified.  For example:-<p>
036:         <xmp>
037:         public class Employee extends SRecordInstance...
038:         public static final SFieldMeta DEPT_ID =
039:         new SFieldString(meta, "DEPT_ID");
040:         static final SFieldMeta DEPARTMENT = new
041:         SFieldReference(meta, Department.meta,
042:         new SFieldMeta[]{DEPT_ID}, 0);
043:         </xmp>
044:        
045:         References are also allowed in primary keys of records, these are
046:         known as <i>Identifying</I> foreign keys.  This means that additional
047:         foreign keys would be added recursively.  See {@Link
048:         simpleorm.examples.BasicTests} for examples.<p>
049:        
050:         Explicitly storing the foreign key fields means that there
051:         is no need to have a <code>Department</code> record instance in order
052:         to retrieve an <code>Employee</code>.  Only if one calls
053:         <code>Employee.getDepartment</code> is the <code>Department</code>
054:         record created.  It also alows overlapping foreign keys to be
055:         supported later (where two References may share a column).<p>
056:        
057:         Fields are normally created in static initializers of class constants
058:         (although this is not necessary).  The java initialization rules
059:         generally work well to ensure that referenced records are initialized
060:         before referencing records.  However, it may occasionally be necessary
061:         to create references in a second pass, particularly if there are
062:         mutually recursive references.<p>
063:        
064:         To understand the underlying data structures you really need to look
065:         at the E-R diagram.<P>
066:        
067:         <img src="../../extraDocs/SOrmUML.png">
068:        
069:         E-Mail Extracts:-
070:         <font size=-1>
071:        
072:         First of all let me note that the problem that you are dealing with is the mapping what used to be called a conceptual model and the relational/logical model.  In the traditional "three schema model" generators work from conceptual through logical to physical models.<p>
073:        
074:         Since the advent of OO technology, the words have changed but the problems remain the same.  Generating the relational schema from the conceptual one used by SimpleORM is quite fiddly, and is the most complex code in SimpleORM.  Going the other way is, in general, much harder -- you are squeezing the toothpaste back into a tube, and not necessarily the same type of tube from whence it came.<p>
075:        
076:         However, in your quick start you do not have to solve all problems.  Just generate the easy, common cases.  Remember that the user can add foreign key definition in their subclass -- there is no reflection.  So please focus on the simple, consistent cases.<p>
077:        
078:         As Richard implies, it is a fundamental assumtion of SimpleORM that records only contain one Primary key, and that that all foreign keys use it.  No candidate keys considered.  This is pretty fundamental to the way SimpleORM works -- the cache is keyed by the primary key, only.<p>
079:        
080:         So that is why you only need to specify the referencing record, but may in general have to specify all the referencing fields.  This is why fields are *not* specified as
081:         SFieldReference(SRecordMeta meta, SFieldMeta[] localKeys, SFieldMeta[] foreignKeys)<p>
082:         which is a relational approach.
083:        
084:         SimpleORM assumes that foreign keys are generally defined in a consistent manner.  This produces succinct code.  I have not tried to make the processing of inconsistent names elegant because I assume (wrongly?) that it is rare. <p>
085:         </font>
086:         */
087:
088:        public class SFieldReference extends SFieldMeta {
089:
090:            /** The direct foreign keys, may not all be scalars.  True inverse
091:             of <code>SFieldMeta.sFieldReference</code>.  Not a flattened
092:             structure like SRecordMeta.sFieldMetas.  You have to recur to
093:             get all the scalar fields in a reference.*/
094:            SFieldMeta[] foreignKeyFields = null;
095:
096:            /** The ultmatiley referenced record whose keys correspond to this
097:             reference's foreign keys.  Ie. the end of the chain.  Not the
098:             same as <code>foreignKeyFields[0].sRecordMeta</code> which is
099:             just one level deep.  <code>SFieldMeta.referencedKeyField</code>
100:             points to correpsonding reference in the
101:             <code>foreignKeyFields[0].sRecordMeta</code> record.*/
102:            SRecordMeta referencedRecord = null;
103:
104:            /** This is the string prepended to any foreign keys.  Eg. to
105:             distinquish <code>ACTING_DEPT_ID</code> vs
106:             <code>PERMANENT_DEPT_ID</code>. */
107:            String prefix = null;
108:
109:            /** Creates a foreign key reference using <code>foreignKeys</code>
110:             to reference <code>referenced</code>.  The <code>foreignKeys</code>
111:             must match the top level primarky keys of <code>referenced</code>
112:             exactly in order, type and number.  If the primaryKey includes
113:             references, then just the reference should be included, not the
114:             indirect foreign keys. <p>
115:             
116:             This raw initializer is only useful to add extra specifications to
117:             the explicit definitions of the foreign key fields.  This is rare in
118:             practice.<p> */
119:            public SFieldReference(SRecordMeta meta, SRecordMeta referenced,
120:                    String fieldName, SFieldMeta[] foreignKeys,
121:                    SPropertyValue[] pvals) {
122:                super (meta, (String) null, fieldName, pvals);
123:                //SLog.slog.debug("SFieldReference1 " + meta + referenced);
124:                setKeys(referenced, "", foreignKeys);
125:            }
126:
127:            public SFieldReference(SRecordMeta meta, SRecordMeta referenced,
128:                    SFieldMeta[] foreignKeys, SPropertyValue[] pvals) {
129:                this (meta, referenced, referenced.getString(SCon.SCOLUMN_NAME),
130:                        foreignKeys, pvals);
131:            }
132:
133:            /** Same as above, but used to reference intermediate foreign keys. */
134:            public SFieldReference(SRecordMeta meta,
135:                    SFieldReference referenced, String fieldName,
136:                    SFieldMeta[] foreignKeys, SPropertyValue[] pvals) {
137:                super (meta, (String) null, fieldName, pvals);
138:                //SLog.slog.debug("SFieldReference1 " + meta + referenced);
139:                setKeys(referenced, "", foreignKeys);
140:            }
141:
142:            public SFieldReference(SRecordMeta meta,
143:                    SFieldReference referenced, SFieldMeta[] foreignKeys,
144:                    SPropertyValue[] pvals) {
145:                this (meta, referenced, referenced.getString(SCon.SCOLUMN_NAME),
146:                        foreignKeys, pvals);
147:            }
148:
149:            /**
150:             * Get the field name to be passed to super-class constructor: if prefix specified,
151:             * us it. Otherwise, use the table name of the referenced table
152:             */
153:            private static String getFieldName(String prefix,
154:                    SRecordMeta referenced) {
155:                if (prefix == null || prefix.equals("")) {
156:                    return referenced.getString(SCon.STABLE_NAME);
157:                } else {
158:                    return ptrim(prefix);
159:                }
160:            }
161:
162:            /**
163:             Creates a <code>SFieldReference</code> field to reference
164:             <code>referenced</code>.  Then creates aditiaonal SFieldMetas that
165:             correspond each column of the foreign key.  A foreign key may in
166:             turn be a reference ("Identifying" foreign key) in which case
167:             this process recurs.<p>
168:             
169:             Each created foreign key column has the same name and type as
170:             the one in the referenced table but the names can be prefixed by
171:             <code>prefix</code> which is handy if for example, an Employee
172:             had a Managing_Department and a Billing_Department.*/
173:            public SFieldReference(SRecordMeta meta, SRecordMeta referenced,
174:                    String prefix, SPropertyValue[] pvals) {
175:                super (meta, (String) null, getFieldName(prefix, referenced),
176:                        pvals);
177:                //SLog.slog.debug("SFieldReference2 " + meta + referenced);
178:                makeForeignKeys(meta, referenced, prefix, pvals);
179:
180:                // #### The handling of properties between references and copies
181:                // needs much more thought!  In particular NOT NULL vs PRIMARY
182:                // KEY!  This was always a latent bug.
183:
184:            }
185:
186:            /** Remove final "_" of prefix. */
187:            private static String ptrim(String prefix) {
188:                int x = prefix.lastIndexOf("_");
189:                if (x == prefix.length() - 1 && prefix.length() != 0)
190:                    return prefix.substring(0, x);
191:                else
192:                    return prefix;
193:            }
194:
195:            public SFieldReference(SRecordMeta meta, SRecordMeta referenced,
196:                    String prefix, SPropertyValue pval1) {
197:                this (meta, referenced, prefix, new SPropertyValue[] { pval1 });
198:            }
199:
200:            public SFieldReference(SRecordMeta meta, SRecordMeta referenced,
201:                    String prefix, SPropertyValue pval1, SPropertyValue pval2) {
202:                this (meta, referenced, prefix, new SPropertyValue[] { pval1,
203:                        pval2 });
204:            }
205:
206:            public SFieldReference(SRecordMeta meta, SRecordMeta referenced,
207:                    String prefix) {
208:                this (meta, referenced, prefix, new SPropertyValue[0]);
209:            }
210:
211:            /** <code>prefix</code> defaults to "", the common case. */
212:            public SFieldReference(SRecordMeta meta, SRecordMeta referenced) {
213:                this (meta, referenced, (String) null);
214:            }
215:
216:            /** For identifying foreign keys. */
217:            public SFieldReference(SRecordMeta meta,
218:                    SFieldReference referenced, String prefix,
219:                    SPropertyValue[] pvals) {
220:                super (meta, (String) null, getFieldName(prefix,
221:                        referenced.referencedRecord), pvals);
222:                //SLog.slog.debug("SFieldReference4 " + meta + referenced + prefix);
223:                makeForeignKeys(meta, referenced, prefix, pvals);
224:            }
225:
226:            /** Create the foreign keys in <code>rmeta</code> that correspond to
227:             the primary keys in <code>referenced</code>.  If
228:             <code>referenced</code> is SRecordMeta then top level, else if
229:             SFieldReference then indirect identifying foreign key. */
230:            private void makeForeignKeys(SRecordMeta rmeta,
231:                    SRecordMeta referenced, String prefix,
232:                    SPropertyValue[] pvals) {
233:
234:                if (isPrimaryKey && rmeta == referenced)
235:                    throw new SException.Error("Identifying Foreign Key "
236:                            + this  + " Cannot recursively reference "
237:                            + referenced);
238:
239:                //SLog.slog.debug("MakeForeignKeys1 " + this + rmeta + referenced);
240:                SArrayList refedKeys = referenced.keySFieldMetas;
241:                SArrayList madeFKeys = new SArrayList(refedKeys.size());
242:
243:                for (int kx = 0; kx < refedKeys.size(); kx++) {
244:                    SFieldMeta key = (SFieldMeta) refedKeys.get(kx);
245:                    if (key.sFieldReference == null) {
246:                        /// A non foreignKey key, create corresponding foreign key.
247:                        SFieldMeta fkey = key.makeForeignKey( //ie Recur
248:                                rmeta, prefix, pvals);
249:                        madeFKeys.add(fkey);
250:                    }
251:                }
252:                SFieldMeta foreignKeys[] = (SFieldMeta[]) madeFKeys
253:                        .toArray(new SFieldMeta[0]);
254:                setKeys(referenced, prefix, foreignKeys);
255:            }
256:
257:            private void makeForeignKeys(SRecordMeta rmeta,
258:                    SFieldReference referenced, String prefix,
259:                    SPropertyValue[] pvals) {
260:
261:                //SLog.slog.debug("MakeForeignKeys2 " + this + rmeta + referenced);
262:                SFieldMeta[] refedKeys = referenced.foreignKeyFields;
263:                SFieldMeta foreignKeys[] = new SFieldMeta[refedKeys.length];
264:
265:                for (int kx = 0; kx < refedKeys.length; kx++) {
266:                    SFieldMeta key = (SFieldMeta) refedKeys[kx];
267:                    SFieldMeta fkey = key.makeForeignKey( //ie Recur
268:                            rmeta, prefix, pvals);
269:                    foreignKeys[kx] = fkey;
270:                }
271:                setKeys(referenced, prefix, foreignKeys);
272:            }
273:
274:            /** Abstract specializer.  Clone this key field to be a foreign key
275:             to <code>rmeta</code> of the same type as this.*/
276:            SFieldMeta makeForeignKey(SRecordMeta rmeta, String prefix,
277:                    SPropertyValue[] pvals) {
278:                return new SFieldReference(rmeta, this , prefix, pvals);
279:            }
280:
281:            /** this record uses (existing) foreignKeys to reference referenced
282:             record.  This method wires that up, setting
283:             <code>sFieldReference</code> and
284:             <code>referencedKeyFields</code>.  It does not create any new
285:             fields.<p>
286:             
287:             Separated from <code>makeForeignKeys()</code> to allow an
288:             explicit list of keys.<p>
289:             
290:             This one is for the top level.*/
291:            private void setKeys(SRecordMeta referenced, String prefix,
292:                    SFieldMeta[] foreignKeys) {
293:
294:                this .referencedRecord = referenced;
295:                this .prefix = prefix == null ? "" : prefix;
296:
297:                /// Run through both referenced.keys and foreign keys.
298:                int fx = -1;
299:                for (int kx = 0; kx < referenced.keySFieldMetas.size(); kx++) {
300:                    SFieldMeta kf = (SFieldMeta) referenced.keySFieldMetas
301:                            .get(kx);
302:                    if (kf.sFieldReference == null) {
303:                        /// A non foreignKey key, create corresponding foreign key.
304:                        fx++;
305:                        SFieldMeta fkey = foreignKeys[fx];
306:                        if (fkey.sFieldReference != null)
307:                            throw new SException.Error(
308:                                    "Overlapping foreign keys not yet supported: "
309:                                            + fkey
310:                                            + " already is a foreign key of "
311:                                            + fkey.sFieldReference);
312:                        if (!kf.getClass().isInstance(fkey))
313:                            throw new SException.Error("Foreign key " + fkey
314:                                    + " not same type as key " + kf);
315:                        if (this .isPrimaryKey != fkey.isPrimaryKey)
316:                            throw new SException.Error(
317:                                    "Inconsistent Primary Key flags " + this 
318:                                            + " vs " + fkey);
319:                        // (Can happen for manually declared foreign keys)
320:                        fkey.sFieldReference = this ;
321:                        fkey.referencedKeyField = kf;
322:                    }
323:                }
324:                this .foreignKeyFields = foreignKeys;
325:                if (foreignKeys.length != fx + 1 || fx == -1)
326:                    throw new SException.Error(
327:                            "Wrong number of non-foregn keys " + (fx + 1));
328:            }
329:
330:            /** For intermediate foreign keys, link up to the referenced <em>Field</em>'s fields.
331:             */
332:            private void setKeys(SFieldReference referenced, String prefix,
333:                    SFieldMeta[] foreignKeys) {
334:
335:                this .referencedRecord = referenced.referencedRecord;
336:                this .prefix = prefix == null ? "" : prefix;
337:
338:                /// Run through both referenced.keys and foreign keys.
339:                SFieldMeta[] refedKeys = referenced.foreignKeyFields;
340:                for (int kx = 0; kx < refedKeys.length; kx++) {
341:                    SFieldMeta kf = refedKeys[kx];
342:                    /// A non foreignKey key, create corresponding foreign key.
343:                    SFieldMeta fkey = foreignKeys[kx];
344:                    if (fkey.sFieldReference != null)
345:                        throw new SException.Error(
346:                                "Overlapping foreign keys not yet supported: "
347:                                        + fkey
348:                                        + " already is a foreign key of "
349:                                        + fkey.sFieldReference);
350:                    if (!kf.getClass().isInstance(fkey))
351:                        throw new SException.Error("Foreign key " + fkey
352:                                + " not instance of key " + kf);
353:                    fkey.sFieldReference = this ;
354:                    fkey.referencedKeyField = kf;
355:                }
356:                this .foreignKeyFields = foreignKeys;
357:            }
358:
359:            public String createColumnSQL() {
360:                throw new SException.Error();
361:            }
362:
363:            /** This reference is updatable iff all its ground foreign keys are
364:             updatable, recursively. */
365:            void checkUpdatable(SRecordInstance instance) {
366:                for (int fx = 0; fx < foreignKeyFields.length; fx++) {
367:                    foreignKeyFields[fx].checkUpdatable(instance);
368:                }
369:            }
370:
371:            /** Specializes SFieldMeta.getRawFieldValue, which is called by
372:             getFieldValue, thence SRecoredInstance.getObject...  <p>
373:             
374:             Normally, if the field is null but all the primary key fields
375:             are non null then does a <code>findOrCreate()</code> to provide
376:             a referenced record.  SQY_REFERENCE_NO_QUERY suppresses this
377:             query.  getReferencedWhileDetached may be called for detached
378:             records.
379:             */
380:            Object getRawFieldValue(SRecordInstance instance, long sqy_flags) {
381:                SRecordInstance result = (SRecordInstance) instance.fieldValues[fieldIndex];
382:                //SLog.slog.debug("getRawFieldValue" + this + instance + result);
383:                if (result != null
384:                        && (!result.isValid() || (instance.isAttached() && !result
385:                                .isAttached()))) { // #Bartek
386:                    // ie. Was not detatched.
387:                    // ## Really should not serialize these in the first place.
388:                    result = null;
389:                }
390:                if (result == null) {
391:                    // references. Putting detached check AFTER check for null reference
392:                    Object[] keys = new Object[foreignKeyFields.length];
393:                    for (int fkx = 0; fkx < foreignKeyFields.length; fkx++) {
394:                        Object fkValue = foreignKeyFields[fkx]
395:                                .getRawFieldValue(instance, sqy_flags);
396:                        // ### no IS_VALID test
397:                        // May recur, and so findOrCreate
398:                        if (fkValue == null)
399:                            return null;
400:                        keys[fkx] = fkValue;
401:                    }
402:
403:                    if (SUte.inBitSet(sqy_flags, SCon.SQY_REFERENCE_NO_QUERY,
404:                            SCon.SQY_))
405:                        return Boolean.FALSE;
406:
407:                    if (instance.isAttached()) {
408:                        result = referencedRecord.findOrCreate(keys, sqy_flags);
409:                    } else // detached... make 'last-ditch' effort to fetch
410:                    {
411:                        result = instance.getReferenceWhileDetached(this , keys);
412:                        if (result == null) {
413:                            throw new SException.Error("Cannot get " + this 
414:                                    + " in Unattached "
415:                                    + instance.toStringDefault());
416:                        }
417:                    }
418:
419:                    instance.fieldValues[fieldIndex] = result; // For next time.
420:                }
421:                return result;
422:            }
423:
424:            /** Sets the instance reference to value.  Then recursively copies
425:             all of the foreign keys.  <code>this</code> must be a top level
426:             foreign key.  (value could be null.)*/
427:            void rawSetFieldValue(SRecordInstance instance, Object value) {
428:                setRawFieldValueRecur(instance, (SRecordInstance) value,
429:                        (SRecordInstance) value);
430:            }
431:
432:            /** Actually sets the instance reference to value recursively.
433:             <code>directRefed</code> is the instance that is directly
434:             referenced from the top level call to
435:             <code>setRawFieldValue</code>.  It is from this record that
436:             values are copied, not from the indirectly referenced records.*/
437:            private void setRawFieldValueRecur(SRecordInstance instance,
438:                    SRecordInstance directRefed, SRecordInstance value) {
439:                if (SLog.slog.enableFields())
440:                    SLog.slog.fields(">RSet " + instance + "." + this  + " = "
441:                            + directRefed + "." + value);
442:                if (directRefed != null && directRefed.fieldValues == null)
443:                    throw new SException.Error("Cannot set " + instance + "."
444:                            + this  + " to Destroyed " + directRefed);
445:                /// Check for bad update orders.
446:                if (value != null) {
447:                    SRecordInstance refedr = (SRecordInstance) value;
448:                    if (refedr.isNewRow()) {
449:                        if (!refedr.isDirty()
450:                                || (refedr.updateListIndex > instance.updateListIndex && instance
451:                                        .isDirty()))
452:                            throw new SException.Error(
453:                                    "Attempt to set "
454:                                            + instance
455:                                            + "."
456:                                            + this 
457:                                            + " to new row "
458:                                            + refedr
459:                                            + " with incorrect update order will produce foreign key violations.");
460:                    }
461:                    if (refedr.isDeleted())
462:                        throw new SException.Error("Attempt to set " + instance
463:                                + "." + this  + " to deleted row " + refedr);
464:                }
465:
466:                //SLog.slog.debug("SRFRecurSetting " + instance + "." + instance.allFields() + "[" + fieldIndex + "] := " + value);
467:
468:                // Set the actual record on instance
469:                // however, DO NOT set it if instance is attached, and value is detached.
470:                // In this latter case, only the keys will be set below
471:                //
472:                // ##Bartek. I think this is now redundant given getRawFieldValue suppresses
473:                // references to detached records.
474:                boolean detachedToAttached = (instance.isAttached()
475:                        && value != null && !value.isAttached());
476:                instance.fieldValues[fieldIndex] = detachedToAttached ? null
477:                        : value;
478:                instance.bitSets[fieldIndex] |= (byte) (SCon.INS_DIRTY | SCon.INS_VALID);
479:
480:                /// Recur through foreign keys
481:                for (int fx = 0; fx < foreignKeyFields.length; fx++) {
482:                    SFieldMeta fkey = foreignKeyFields[fx];
483:                    SFieldMeta refed = fkey.referencedKeyField;
484:                    //SLog.slog.debug("SRFRecur #" + fx + fkey + refed + directRefed); // DR == null
485:                    Object newValue =
486:                    // value==null?null:directRefed.fieldValues[refed.fieldIndex]; // !!! Old
487:                    directRefed == null ? null
488:                            : directRefed.fieldValues[refed.fieldIndex]; // Corrected?
489:
490:                    // Issue is that if we deliberately set the value to null (Basic
491:                    // Tests) there is no looked up value, get directRefed == null.
492:                    // But in IdentFKeys we only retrieve the Payslip, not the
493:                    // Employee rec, and so Empee ref is null although Empee Nr is
494:                    // not.
495:
496:                    // Maybe should use getRawFieldValue?
497:                    //SLog.slog.debug("SRFRecur " + fx + fkey + refed  + "[" + refed.fieldIndex + "] :=" + newValue);
498:                    if (fkey instanceof  SFieldReference)
499:                        ((SFieldReference) fkey).setRawFieldValueRecur(
500:                                instance, directRefed,
501:                                (SRecordInstance) newValue);
502:                    else
503:                        fkey.rawSetFieldValue(instance, newValue);
504:                    // ## Not OK if overlapping fkeys.
505:                }
506:                //SLog.slog.debug("<");
507:            }
508:
509:            /** Returns the field definition of the <code>index</code>th foreign
510:             key for this reference.  The first one is 0.  This can then be used
511:             as a parameter to subsequent get*() methods.  <p>
512:             
513:             The main use of this function is to access the foreing key values of
514:             references without having to actually query the database.  <p>
515:             
516:             (Note that
517:             this purpose will become obsolete once the lazy
518:             <code>findOrCreate</code> is implemented because just referencing
519:             the key value of the referenced object will not trigger the
520:             query.) */
521:            public SFieldMeta foreignKeyField(int index) {
522:                return foreignKeyFields[index];
523:            }
524:
525:            /** Number of foreign key fields for this reference. */
526:            public int foreignKeyFieldsSize() {
527:                return foreignKeyFields.length;
528:            }
529:
530:            /**
531:             * Get the SRecordMeta to which this reference points to.
532:             * Will not attempt to retrieve the record from the database,
533:             * will return null if not in memory.
534:             */
535:            public SRecordMeta getReferencedRecord() {
536:                return this .referencedRecord;
537:            }
538:
539:            public String toString() {
540:                /// Make prety referenceName
541:                return "[FR "
542:                        + (sRecordMeta != null ? SUte
543:                                .cleanClass(sRecordMeta.userClass) : "NULL")
544:                        + "."
545:                        + prefix
546:                        + "_"
547:                        + (referencedRecord != null ? SUte
548:                                .cleanClass(referencedRecord.userClass)
549:                                : "NULL") + "]";
550:            }
551:
552:            public String toLongerString() {
553:                StringBuffer res = new StringBuffer("[FRL "
554:                        + super .toLongerString() + " RefedRec "
555:                        + referencedRecord + " FKeyFlds ");
556:                res.append(SUte.arrayToString(foreignKeyFields));
557:                res.append("]");
558:                return res.toString();
559:            }
560:
561:            Object queryFieldValue(ResultSet rs, int sqlIndex) {
562:                throw new SException.InternalError("Attempt to query " + this );
563:            }
564:
565:            Object convertToField(Object raw) throws Exception {
566:                Class refed = referencedRecord.userClass;
567:                if (raw != null && !refed.isInstance(raw))
568:                    throw new SException.Error("Object " + raw + " not a "
569:                            + refed.getName());
570:                return raw;
571:            }
572:
573:            /** Specializes SFieldMeta. */
574:            String defaultDataType() {
575:                throw new SException.InternalError(
576:                        "SFieldReference has no datatype.");
577:            }
578:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.