1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2002,2008 Oracle. All rights reserved. 5 * 6 * $Id: SecondaryIndex.java,v 1.1 2008/02/07 17:12:26 mark Exp $ 7 */ 8 9package com.sleepycat.persist; 10 11import java.io.FileNotFoundException; 12import java.util.Map; 13import java.util.SortedMap; 14 15import com.sleepycat.bind.EntityBinding; 16import com.sleepycat.bind.EntryBinding; 17import com.sleepycat.collections.StoredSortedMap; 18import com.sleepycat.compat.DbCompat; 19import com.sleepycat.db.Database; 20import com.sleepycat.db.DatabaseConfig; 21import com.sleepycat.db.DatabaseEntry; 22import com.sleepycat.db.DatabaseException; 23import com.sleepycat.db.LockMode; 24import com.sleepycat.db.OperationStatus; 25import com.sleepycat.db.SecondaryDatabase; 26import com.sleepycat.db.Transaction; 27import com.sleepycat.persist.model.DeleteAction; 28import com.sleepycat.persist.model.Relationship; 29import com.sleepycat.persist.model.SecondaryKey; 30 31/** 32 * The secondary index for an entity class and a secondary key. 33 * 34 * <p>{@code SecondaryIndex} objects are thread-safe. Multiple threads may 35 * safely call the methods of a shared {@code SecondaryIndex} object.</p> 36 * 37 * <p>{@code SecondaryIndex} implements {@link EntityIndex} to map the 38 * secondary key type (SK) to the entity type (E). In other words, entities 39 * are accessed by secondary key values.</p> 40 * 41 * <p>The {@link SecondaryKey} annotation may be used to define a secondary key 42 * as shown in the following example.</p> 43 * 44 * <pre class="code"> 45 * {@literal @Entity} 46 * class Employee { 47 * 48 * {@literal @PrimaryKey} 49 * long id; 50 * 51 * {@literal @SecondaryKey(relate=MANY_TO_ONE)} 52 * String department; 53 * 54 * String name; 55 * 56 * private Employee() {} 57 * }</pre> 58 * 59 * <p>Before obtaining a {@code SecondaryIndex}, the {@link PrimaryIndex} must 60 * be obtained for the entity class. To obtain the {@code SecondaryIndex} call 61 * {@link EntityStore#getSecondaryIndex EntityStore.getSecondaryIndex}, passing 62 * the primary index, the secondary key class and the secondary key name. For 63 * example:</p> 64 * 65 * <pre class="code"> 66 * EntityStore store = new EntityStore(...); 67 * 68 * {@code PrimaryIndex<Long,Employee>} primaryIndex = 69 * store.getPrimaryIndex(Long.class, Employee.class); 70 * 71 * {@code SecondaryIndex<String,Long,Employee>} secondaryIndex = 72 * store.getSecondaryIndex(primaryIndex, String.class, "department");</pre> 73 * 74 * <p>Since {@code SecondaryIndex} implements the {@link EntityIndex} 75 * interface, it shares the common index methods for retrieving and deleting 76 * entities, opening cursors and using transactions. See {@link EntityIndex} 77 * for more information on these topics.</p> 78 * 79 * <p>{@code SecondaryIndex} does <em>not</em> provide methods for inserting 80 * and updating entities. That must be done using the {@link 81 * PrimaryIndex}.</p> 82 * 83 * <p>Note that a {@code SecondaryIndex} has three type parameters {@code 84 * <SK,PK,E>} or in the example {@code <String,Long,Employee>} while a {@link 85 * PrimaryIndex} has only two type parameters {@code <PK,E>} or {@code 86 * <Long,Employee>}. This is because a {@code SecondaryIndex} has an extra 87 * level of mapping: It maps from secondary key to primary key, and then from 88 * primary key to entity. For example, consider this entity:</p> 89 * 90 * <p><table class="code" border="1"> 91 * <tr><th>ID</th><th>Department</th><th>Name</th></tr> 92 * <tr><td>1</td><td>Engineering</td><td>Jane Smith</td></tr> 93 * </table></p> 94 * 95 * <p>The {@link PrimaryIndex} maps from id directly to the entity, or from 96 * primary key 1 to the "Jane Smith" entity in the example. The {@code 97 * SecondaryIndex} maps from department to id, or from secondary key 98 * "Engineering" to primary key 1 in the example, and then uses the {@code 99 * PrimaryIndex} to map from the primary key to the entity.</p> 100 * 101 * <p>Because of this extra type parameter and extra level of mapping, a {@code 102 * SecondaryIndex} can provide more than one mapping, or view, of the entities 103 * in the primary index. The main mapping of a {@code SecondaryIndex} is to 104 * map from secondary key (SK) to entity (E), or in the example, from the 105 * String department key to the Employee entity. The {@code SecondaryIndex} 106 * itself, by implementing {@code EntityIndex<SK,E>}, provides this 107 * mapping.</p> 108 * 109 * <p>The second mapping provided by {@code SecondaryIndex} is from secondary 110 * key (SK) to primary key (PK), or in the example, from the String department 111 * key to the Long id key. The {@link #keysIndex} method provides this 112 * mapping. When accessing the keys index, the primary key is returned rather 113 * than the entity. When only the primary key is needed and not the entire 114 * entity, using the keys index is less expensive than using the secondary 115 * index because the primary index does not have to be accessed.</p> 116 * 117 * <p>The third mapping provided by {@code SecondaryIndex} is from primary key 118 * (PK) to entity (E), for the subset of entities having a given secondary key 119 * (SK). This mapping is provided by the {@link #subIndex} method. A 120 * sub-index is convenient when you are interested in working with the subset 121 * of entities having a particular secondary key value, for example, all 122 * employees in a given department.</p> 123 * 124 * <p>All three mappings, along with the mapping provided by the {@link 125 * PrimaryIndex}, are shown using example data in the {@link EntityIndex} 126 * interface documentation. See {@link EntityIndex} for more information.</p> 127 * 128 * <p>Note that when using an index, keys and values are stored and retrieved 129 * by value not by reference. In other words, if an entity object is stored 130 * and then retrieved, or retrieved twice, each object will be a separate 131 * instance. For example, in the code below the assertion will always 132 * fail.</p> 133 * <pre class="code"> 134 * MyKey key = ...; 135 * MyEntity entity1 = index.get(key); 136 * MyEntity entity2 = index.get(key); 137 * assert entity1 == entity2; // always fails! 138 * </pre> 139 * 140 * <h3>One-to-One Relationships</h3> 141 * 142 * <p>A {@link Relationship#ONE_TO_ONE ONE_TO_ONE} relationship, although less 143 * common than other types of relationships, is the simplest type of 144 * relationship. A single entity is related to a single secondary key value. 145 * For example:</p> 146 * 147 * <pre class="code"> 148 * {@literal @Entity} 149 * class Employee { 150 * 151 * {@literal @PrimaryKey} 152 * long id; 153 * 154 * {@literal @SecondaryKey(relate=ONE_TO_ONE)} 155 * String ssn; 156 * 157 * String name; 158 * 159 * private Employee() {} 160 * } 161 * 162 * {@code SecondaryIndex<String,Long,Employee>} employeeBySsn = 163 * store.getSecondaryIndex(primaryIndex, String.class, "ssn");</pre> 164 * 165 * <p>With a {@link Relationship#ONE_TO_ONE ONE_TO_ONE} relationship, the 166 * secondary key must be unique; in other words, no two entities may have the 167 * same secondary key value. If an attempt is made to store an entity having 168 * the same secondary key value as another existing entity, a {@link 169 * DatabaseException} will be thrown.</p> 170 * 171 * <p>Because the secondary key is unique, it is useful to lookup entities by 172 * secondary key using {@link EntityIndex#get}. For example:</p> 173 * 174 * <pre class="code"> 175 * Employee employee = employeeBySsn.get(mySsn);</pre> 176 * 177 * <h3>Many-to-One Relationships</h3> 178 * 179 * <p>A {@link Relationship#MANY_TO_ONE MANY_TO_ONE} relationship is the most 180 * common type of relationship. One or more entities is related to a single 181 * secondary key value. For example:</p> 182 * 183 * <pre class="code"> 184 * {@literal @Entity} 185 * class Employee { 186 * 187 * {@literal @PrimaryKey} 188 * long id; 189 * 190 * {@literal @SecondaryKey(relate=MANY_TO_ONE)} 191 * String department; 192 * 193 * String name; 194 * 195 * private Employee() {} 196 * } 197 * 198 * {@code SecondaryIndex<String,Long,Employee>} employeeByDepartment = 199 * store.getSecondaryIndex(primaryIndex, String.class, "department");</pre> 200 * 201 * <p>With a {@link Relationship#MANY_TO_ONE MANY_TO_ONE} relationship, the 202 * secondary key is not required to be unique; in other words, more than one 203 * entity may have the same secondary key value. In this example, more than 204 * one employee may belong to the same department.</p> 205 * 206 * <p>The most convenient way to access the employees in a given department is 207 * by using a sub-index. For example:</p> 208 * 209 * <pre class="code"> 210 * {@code EntityIndex<Long,Entity>} subIndex = employeeByDepartment.subIndex(myDept); 211 * {@code EntityCursor<Employee>} cursor = subIndex.entities(); 212 * try { 213 * for (Employee entity : cursor) { 214 * // Do something with the entity... 215 * } 216 * } finally { 217 * cursor.close(); 218 * }</pre> 219 * 220 * <h3>One-to-Many Relationships</h3> 221 * 222 * <p>In a {@link Relationship#ONE_TO_MANY ONE_TO_MANY} relationship, a single 223 * entity is related to one or more secondary key values. For example:</p> 224 * 225 * <pre class="code"> 226 * {@literal @Entity} 227 * class Employee { 228 * 229 * {@literal @PrimaryKey} 230 * long id; 231 * 232 * {@literal @SecondaryKey(relate=ONE_TO_MANY)} 233 * {@literal Set<String> emailAddresses = new HashSet<String>;} 234 * 235 * String name; 236 * 237 * private Employee() {} 238 * } 239 * 240 * {@code SecondaryIndex<String,Long,Employee>} employeeByEmail = 241 * store.getSecondaryIndex(primaryIndex, String.class, "emailAddresses");</pre> 242 * 243 * <p>With a {@link Relationship#ONE_TO_MANY ONE_TO_MANY} relationship, the 244 * secondary key must be unique; in other words, no two entities may have the 245 * same secondary key value. In this example, no two employees may have the 246 * same email address. If an attempt is made to store an entity having the 247 * same secondary key value as another existing entity, a {@link 248 * DatabaseException} will be thrown.</p> 249 * 250 * <p>Because the secondary key is unique, it is useful to lookup entities by 251 * secondary key using {@link EntityIndex#get}. For example:</p> 252 * 253 * <pre class="code"> 254 * Employee employee = employeeByEmail.get(myEmailAddress);</pre> 255 * 256 * <p>The secondary key field for a {@link Relationship#ONE_TO_MANY 257 * ONE_TO_MANY} relationship must be an array or collection type. To access 258 * the email addresses of an employee, simply access the collection field 259 * directly. For example:</p> 260 * 261 * <pre class="code"> 262 * Employee employee = primaryIndex.get(1); // Get the entity by primary key 263 * employee.emailAddresses.add(myNewEmail); // Add an email address 264 * primaryIndex.putNoReturn(1, employee); // Update the entity</pre> 265 * 266 * <h3>Many-to-Many Relationships</h3> 267 * 268 * <p>In a {@link Relationship#MANY_TO_MANY MANY_TO_MANY} relationship, one 269 * or more entities is related to one or more secondary key values. For 270 * example:</p> 271 * 272 * <pre class="code"> 273 * {@literal @Entity} 274 * class Employee { 275 * 276 * {@literal @PrimaryKey} 277 * long id; 278 * 279 * {@literal @SecondaryKey(relate=MANY_TO_MANY)} 280 * {@literal Set<String> organizations = new HashSet<String>;} 281 * 282 * String name; 283 * 284 * private Employee() {} 285 * } 286 * 287 * {@code SecondaryIndex<String,Long,Employee>} employeeByOrganization = 288 * store.getSecondaryIndex(primaryIndex, String.class, "organizations");</pre> 289 * 290 * <p>With a {@link Relationship#MANY_TO_MANY MANY_TO_MANY} relationship, the 291 * secondary key is not required to be unique; in other words, more than one 292 * entity may have the same secondary key value. In this example, more than 293 * one employee may belong to the same organization.</p> 294 * 295 * <p>The most convenient way to access the employees in a given organization 296 * is by using a sub-index. For example:</p> 297 * 298 * <pre class="code"> 299 * {@code EntityIndex<Long,Entity>} subIndex = employeeByOrganization.subIndex(myOrg); 300 * {@code EntityCursor<Employee>} cursor = subIndex.entities(); 301 * try { 302 * for (Employee entity : cursor) { 303 * // Do something with the entity... 304 * } 305 * } finally { 306 * cursor.close(); 307 * }</pre> 308 * 309 * <p>The secondary key field for a {@link Relationship#MANY_TO_MANY 310 * MANY_TO_MANY} relationship must be an array or collection type. To access 311 * the organizations of an employee, simply access the collection field 312 * directly. For example:</p> 313 * 314 * <pre class="code"> 315 * Employee employee = primaryIndex.get(1); // Get the entity by primary key 316 * employee.organizations.remove(myOldOrg); // Remove an organization 317 * primaryIndex.putNoReturn(1, employee); // Update the entity</pre> 318 * 319 * <h3>Foreign Key Constraints for Related Entities</h3> 320 * 321 * <p>In all the examples above the secondary key is treated only as a simple 322 * value, such as a {@code String} department field. In many cases, that is 323 * sufficient. But in other cases, you may wish to constrain the secondary 324 * keys of one entity class to be valid primary keys of another entity 325 * class. For example, a Department entity may also be defined:</p> 326 * 327 * <pre class="code"> 328 * {@literal @Entity} 329 * class Department { 330 * 331 * {@literal @PrimaryKey} 332 * String name; 333 * 334 * String missionStatement; 335 * 336 * private Department() {} 337 * }</pre> 338 * 339 * <p>You may wish to constrain the department field values of the Employee 340 * class in the examples above to be valid primary keys of the Department 341 * entity class. In other words, you may wish to ensure that the department 342 * field of an Employee will always refer to a valid Department entity.</p> 343 * 344 * <p>You can implement this constraint yourself by validating the department 345 * field before you store an Employee. For example:</p> 346 * 347 * <pre class="code"> 348 * {@code PrimaryIndex<String,Department>} departmentIndex = 349 * store.getPrimaryIndex(String.class, Department.class); 350 * 351 * void storeEmployee(Employee employee) throws DatabaseException { 352 * if (departmentIndex.contains(employee.department)) { 353 * primaryIndex.putNoReturn(employee); 354 * } else { 355 * throw new IllegalArgumentException("Department does not exist: " + 356 * employee.department); 357 * } 358 * }</pre> 359 * 360 * <p>Or, instead you could define the Employee department field as a foreign 361 * key, and this validation will be done for you when you attempt to store the 362 * Employee entity. For example:</p> 363 * 364 * <pre class="code"> 365 * {@literal @Entity} 366 * class Employee { 367 * 368 * {@literal @PrimaryKey} 369 * long id; 370 * 371 * {@literal @SecondaryKey(relate=MANY_TO_ONE, relatedEntity=Department.class)} 372 * String department; 373 * 374 * String name; 375 * 376 * private Employee() {} 377 * }</pre> 378 * 379 * <p>The {@code relatedEntity=Department.class} above defines the department 380 * field as a foreign key that refers to a Department entity. Whenever a 381 * Employee entity is stored, its department field value will be checked to 382 * ensure that a Department entity exists with that value as its primary key. 383 * If no such Department entity exists, then a {@link DatabaseException} is 384 * thrown, causing the transaction to be aborted (assuming that transactions 385 * are used).</p> 386 * 387 * <p>This begs the question: What happens when a Department entity is deleted 388 * while one or more Employee entities have department fields that refer to 389 * the deleted department's primary key? If the department were allowed to be 390 * deleted, the foreign key constraint for the Employee department field would 391 * be violated, because the Employee department field would refer to a 392 * department that does not exist.</p> 393 * 394 * <p>By default, when this situation arises the system does not allow the 395 * department to be deleted. Instead, a {@link DatabaseException} is thrown, 396 * causing the transaction to be aborted. In this case, in order to delete a 397 * department, the department field of all Employee entities must first be 398 * updated to refer to a different existing department, or set to null. This 399 * is the responsibility of the application.</p> 400 * 401 * <p>There are two additional ways of handling deletion of a Department 402 * entity. These alternatives are configured using the {@link 403 * SecondaryKey#onRelatedEntityDelete} annotation property. Setting this 404 * property to {@link DeleteAction#NULLIFY} causes the Employee department 405 * field to be automatically set to null when the department they refer to is 406 * deleted. This may or may not be desirable, depending on application 407 * policies. For example:</p> 408 * 409 * <pre class="code"> 410 * {@literal @Entity} 411 * class Employee { 412 * 413 * {@literal @PrimaryKey} 414 * long id; 415 * 416 * {@code @SecondaryKey(relate=MANY_TO_ONE, relatedEntity=Department.class, 417 * onRelatedEntityDelete=NULLIFY)} 418 * String department; 419 * 420 * String name; 421 * 422 * private Employee() {} 423 * }</pre> 424 * 425 * <p>The {@link DeleteAction#CASCADE} value, on the other hand, causes the 426 * Employee entities to be automatically deleted when the department they refer 427 * to is deleted. This is probably not desirable in this particular example, 428 * but is useful for parent-child relationships. For example:</p> 429 * 430 * <pre class="code"> 431 * {@literal @Entity} 432 * class Order { 433 * 434 * {@literal @PrimaryKey} 435 * long id; 436 * 437 * String description; 438 * 439 * private Order() {} 440 * } 441 * 442 * {@literal @Entity} 443 * class OrderItem { 444 * 445 * {@literal @PrimaryKey} 446 * long id; 447 * 448 * {@code @SecondaryKey(relate=MANY_TO_ONE, relatedEntity=Order.class, 449 * onRelatedEntityDelete=CASCADE)} 450 * long orderId; 451 * 452 * String description; 453 * 454 * private OrderItem() {} 455 * }</pre> 456 * 457 * <p>The OrderItem orderId field refers to its "parent" Order entity. When an 458 * Order entity is deleted, it may be useful to automatically delete its 459 * "child" OrderItem entities.</p> 460 * 461 * <p>For more information, see {@link SecondaryKey#onRelatedEntityDelete}.</p> 462 * 463 * <h3>One-to-Many versus Many-to-One for Related Entities</h3> 464 * 465 * <p>When there is a conceptual Many-to-One relationship such as Employee to 466 * Department as illustrated in the examples above, the relationship may be 467 * implemented either as Many-to-One in the Employee class or as One-to-Many in 468 * the Department class.</p> 469 * 470 * <p>Here is the Many-to-One approach.</p> 471 * 472 * <pre class="code"> 473 * {@literal @Entity} 474 * class Employee { 475 * 476 * {@literal @PrimaryKey} 477 * long id; 478 * 479 * {@literal @SecondaryKey(relate=MANY_TO_ONE, relatedEntity=Department.class)} 480 * String department; 481 * 482 * String name; 483 * 484 * private Employee() {} 485 * } 486 * 487 * {@literal @Entity} 488 * class Department { 489 * 490 * {@literal @PrimaryKey} 491 * String name; 492 * 493 * String missionStatement; 494 * 495 * private Department() {} 496 * }</pre> 497 * 498 * <p>And here is the One-to-Many approach.</p> 499 * 500 * <pre class="code"> 501 * {@literal @Entity} 502 * class Employee { 503 * 504 * {@literal @PrimaryKey} 505 * long id; 506 * 507 * String name; 508 * 509 * private Employee() {} 510 * } 511 * 512 * {@literal @Entity} 513 * class Department { 514 * 515 * {@literal @PrimaryKey} 516 * String name; 517 * 518 * String missionStatement; 519 * 520 * {@literal @SecondaryKey(relate=ONE_TO_MANY, relatedEntity=Employee.class)} 521 * {@literal Set<Long> employees = new HashSet<Long>;} 522 * 523 * private Department() {} 524 * }</pre> 525 * 526 * <p>Which approach is best? The Many-to-One approach better handles large 527 * number of entities on the to-Many side of the relationship because it 528 * doesn't store a collection of keys as an entity field. With Many-to-One a 529 * Btree is used to store the collection of keys and the Btree can easily 530 * handle very large numbers of keys. With One-to-Many, each time a related 531 * key is added or removed the entity on the One side of the relationship, 532 * along with the complete collection of related keys, must be updated. 533 * Therefore, if large numbers of keys may be stored per relationship, 534 * Many-to-One is recommended.</p> 535 * 536 * <p>If the number of entities per relationship is not a concern, then you may 537 * wish to choose the approach that is most natural in your application data 538 * model. For example, if you think of a Department as containing employees 539 * and you wish to modify the Department object each time an employee is added 540 * or removed, then you may wish to store a collection of Employee keys in the 541 * Department object (One-to-Many).</p> 542 * 543 * <p>Note that if you have a One-to-Many relationship and there is no related 544 * entity, then you don't have a choice -- you have to use One-to-Many because 545 * there is no entity on the to-Many side of the relationship where a 546 * Many-to-One key could be defined. An example is the Employee to email 547 * addresses relationship discussed above:</p> 548 * 549 * <pre class="code"> 550 * {@literal @Entity} 551 * class Employee { 552 * 553 * {@literal @PrimaryKey} 554 * long id; 555 * 556 * {@literal @SecondaryKey(relate=ONE_TO_MANY)} 557 * {@literal Set<String> emailAddresses = new HashSet<String>;} 558 * 559 * String name; 560 * 561 * private Employee() {} 562 * }</pre> 563 * 564 * <p>For sake of argument imagine that each employee has thousands of email 565 * addresses and employees frequently add and remove email addresses. To 566 * avoid the potential performance problems associated with updating the 567 * Employee entity every time an email address is added or removed, you could 568 * create an EmployeeEmailAddress entity and use a Many-to-One relationship as 569 * shown below:</p> 570 * 571 * <pre class="code"> 572 * {@literal @Entity} 573 * class Employee { 574 * 575 * {@literal @PrimaryKey} 576 * long id; 577 * 578 * String name; 579 * 580 * private Employee() {} 581 * } 582 * 583 * {@literal @Entity} 584 * class EmployeeEmailAddress { 585 * 586 * {@literal @PrimaryKey} 587 * String emailAddress; 588 * 589 * {@literal @SecondaryKey(relate=MANY_TO_ONE, relatedEntity=Employee.class)} 590 * long employeeId; 591 * 592 * private EmployeeEmailAddress() {} 593 * }</pre> 594 * 595 * <h3>Key Placement with Many-to-Many for Related Entities</h3> 596 * 597 * <p>As discussed in the section above, one drawback of a to-Many relationship 598 * (One-to-Many was discussed above and Many-to-Many is discussed here) is that 599 * it requires storing a collection of keys in an entity. Each time a key is 600 * added or removed, the containing entity must be updated. This has potential 601 * performance problems when there are large numbers of entities on the to-Many 602 * side of the relationship, in other words, when there are large numbers of 603 * keys in each secondary key field collection.</p> 604 * 605 * <p>If you have a Many-to-Many relationship with a reasonably small number of 606 * entities on one side of the relationship and a large number of entities on 607 * the other side, you can avoid the potential performance problems by defining 608 * the secondary key field on the side with a small number of entities.</p> 609 * 610 * <p>For example, in an Employee-to-Organization relationship, the number of 611 * organizations per employee will normally be reasonably small but the number 612 * of employees per organization may be very large. Therefore, to avoid 613 * potential performance problems, the secondary key field should be defined in 614 * the Employee class as shown below.</p> 615 * 616 * <pre class="code"> 617 * {@literal @Entity} 618 * class Employee { 619 * 620 * {@literal @PrimaryKey} 621 * long id; 622 * 623 * {@literal @SecondaryKey(relate=MANY_TO_MANY, relatedEntity=Organization.class)} 624 * {@literal Set<String> organizations = new HashSet<String>;} 625 * 626 * String name; 627 * 628 * private Employee() {} 629 * } 630 * 631 * {@literal @Entity} 632 * class Organization { 633 * 634 * {@literal @PrimaryKey} 635 * String name; 636 * 637 * String description; 638 * }</pre> 639 * 640 * <p>If instead a {@code Set<Long> members} key had been defined in the 641 * Organization class, this set could potentially have a large number of 642 * elements and performance problems could result.</p> 643 * 644 * <h3>Many-to-Many Versus a Relationship Entity</h3> 645 * 646 * <p>If you have a Many-to-Many relationship with a large number of entities 647 * on <em>both</em> sides of the relationship, you can avoid the potential 648 * performance problems by using a <em>relationship entity</em>. A 649 * relationship entity defines the relationship between two other entities 650 * using two Many-to-One relationships.</p> 651 * 652 * <p>Imagine a relationship between cars and trucks indicating whenever a 653 * particular truck was passed on the road by a particular car. A given car 654 * may pass a large number of trucks and a given truck may be passed by a large 655 * number of cars. First look at a Many-to-Many relationship between these two 656 * entities:</p> 657 * 658 * <pre class="code"> 659 * {@literal @Entity} 660 * class Car { 661 * 662 * {@literal @PrimaryKey} 663 * String licenseNumber; 664 * 665 * {@literal @SecondaryKey(relate=MANY_TO_MANY, relatedEntity=Truck.class)} 666 * {@literal Set<String> trucksPassed = new HashSet<String>;} 667 * 668 * String color; 669 * 670 * private Car() {} 671 * } 672 * 673 * {@literal @Entity} 674 * class Truck { 675 * 676 * {@literal @PrimaryKey} 677 * String licenseNumber; 678 * 679 * int tons; 680 * 681 * private Truck() {} 682 * }</pre> 683 * 684 * <p>With the Many-to-Many approach above, the {@code trucksPassed} set could 685 * potentially have a large number of elements and performance problems could 686 * result.</p> 687 * 688 * <p>To apply the relationship entity approach we define a new entity class 689 * named CarPassedTruck representing a single truck passed by a single car. We 690 * remove the secondary key from the Car class and use two secondary keys in 691 * the CarPassedTruck class instead.</p> 692 * 693 * <pre class="code"> 694 * {@literal @Entity} 695 * class Car { 696 * 697 * {@literal @PrimaryKey} 698 * String licenseNumber; 699 * 700 * String color; 701 * 702 * private Car() {} 703 * } 704 * 705 * {@literal @Entity} 706 * class Truck { 707 * 708 * {@literal @PrimaryKey} 709 * String licenseNumber; 710 * 711 * int tons; 712 * 713 * private Truck() {} 714 * } 715 * 716 * {@literal @Entity} 717 * class CarPassedTruck { 718 * 719 * {@literal @PrimaryKey} 720 * long id; 721 * 722 * {@literal @SecondaryKey(relate=MANY_TO_ONE, relatedEntity=Car.class)} 723 * String carLicense; 724 * 725 * {@literal @SecondaryKey(relate=MANY_TO_ONE, relatedEntity=Truck.class)} 726 * String truckLicense; 727 * 728 * private CarPassedTruck() {} 729 * }</pre> 730 * 731 * <p>The CarPassedTruck entity can be used to access the relationship by car 732 * license or by truck license.</p> 733 * 734 * <p>You may use the relationship entity approach because of the potential 735 * performance problems mentioned above. Or, you may choose to use this 736 * approach in order to store other information about the relationship. For 737 * example, if for each car that passes a truck you wish to record how much 738 * faster the car was going than the truck, then a relationship entity is the 739 * logical place to store that property. In the example below the 740 * speedDifference property is added to the CarPassedTruck class.</p> 741 * 742 * <pre class="code"> 743 * {@literal @Entity} 744 * class CarPassedTruck { 745 * 746 * {@literal @PrimaryKey} 747 * long id; 748 * 749 * {@literal @SecondaryKey(relate=MANY_TO_ONE, relatedEntity=Car.class)} 750 * String carLicense; 751 * 752 * {@literal @SecondaryKey(relate=MANY_TO_ONE, relatedEntity=Truck.class)} 753 * String truckLicense; 754 * 755 * int speedDifference; 756 * 757 * private CarPassedTruck() {} 758 * }</pre> 759 * 760 * <p>Be aware that the relationship entity approach adds overhead compared to 761 * Many-to-Many. There is one additional entity and one additional secondary 762 * key. These factors should be weighed against its advantages and the 763 * relevant application access patterns should be considered.</p> 764 * 765 * @author Mark Hayes 766 */ 767public class SecondaryIndex<SK,PK,E> extends BasicIndex<SK,E> { 768 769 private SecondaryDatabase secDb; 770 private Database keysDb; 771 private PrimaryIndex priIndex; 772 private EntityBinding entityBinding; 773 private EntityIndex<SK,PK> keysIndex; 774 private SortedMap<SK,E> map; 775 776 /** 777 * Creates a secondary index without using an <code>EntityStore</code>. 778 * When using an {@link EntityStore}, call {@link 779 * EntityStore#getSecondaryIndex getSecondaryIndex} instead. 780 * 781 * <p>This constructor is not normally needed and is provided for 782 * applications that wish to use custom bindings along with the Direct 783 * Persistence Layer. Normally, {@link EntityStore#getSecondaryIndex 784 * getSecondaryIndex} is used instead.</p> 785 * 786 * @param database the secondary database used for all access other than 787 * via a {@link #keysIndex}. 788 * 789 * @param keysDatabase another handle on the secondary database, opened 790 * without association to the primary, and used only for access via a 791 * {@link #keysIndex}. If this argument is null and the {@link #keysIndex} 792 * method is called, then the keys database will be opened automatically; 793 * however, the user is then responsible for closing the keys database. To 794 * get the keys database in order to close it, call {@link 795 * #getKeysDatabase}. 796 * 797 * @param primaryIndex the primary index associated with this secondary 798 * index. 799 * 800 * @param secondaryKeyClass the class of the secondary key. 801 * 802 * @param secondaryKeyBinding the binding to be used for secondary keys. 803 */ 804 public SecondaryIndex(SecondaryDatabase database, 805 Database keysDatabase, 806 PrimaryIndex<PK,E> primaryIndex, 807 Class<SK> secondaryKeyClass, 808 EntryBinding secondaryKeyBinding) 809 throws DatabaseException { 810 811 super(database, secondaryKeyClass, secondaryKeyBinding, 812 new EntityValueAdapter(primaryIndex.getEntityClass(), 813 primaryIndex.getEntityBinding(), 814 true)); 815 secDb = database; 816 keysDb = keysDatabase; 817 priIndex = primaryIndex; 818 entityBinding = primaryIndex.getEntityBinding(); 819 } 820 821 /** 822 * Returns the underlying secondary database for this index. 823 * 824 * @return the secondary database. 825 */ 826 public SecondaryDatabase getDatabase() { 827 return secDb; 828 } 829 830 /** 831 * Returns the underlying secondary database that is not associated with 832 * the primary database and is used for the {@link #keysIndex}. 833 * 834 * @return the keys database. 835 */ 836 public Database getKeysDatabase() { 837 return keysDb; 838 } 839 840 /** 841 * Returns the primary index associated with this secondary index. 842 * 843 * @return the primary index. 844 */ 845 public PrimaryIndex<PK,E> getPrimaryIndex() { 846 return priIndex; 847 } 848 849 /** 850 * Returns the secondary key class for this index. 851 * 852 * @return the class. 853 */ 854 public Class<SK> getKeyClass() { 855 return keyClass; 856 } 857 858 /** 859 * Returns the secondary key binding for the index. 860 * 861 * @return the key binding. 862 */ 863 public EntryBinding getKeyBinding() { 864 return keyBinding; 865 } 866 867 /** 868 * Returns a read-only keys index that maps secondary key to primary key. 869 * When accessing the keys index, the primary key is returned rather than 870 * the entity. When only the primary key is needed and not the entire 871 * entity, using the keys index is less expensive than using the secondary 872 * index because the primary index does not have to be accessed. 873 * 874 * <p>Note the following in the unusual case that you are <em>not</em> 875 * using an <code>EntityStore</code>: This method will open the keys 876 * database, a second database handle for the secondary database, if it is 877 * not already open. In this case, if you are <em>not</em> using an 878 * <code>EntityStore</code>, then you are responsible for closing the 879 * database returned by {@link #getKeysDatabase} before closing the 880 * environment. If you <em>are</em> using an <code>EntityStore</code>, the 881 * keys database will be closed automatically by {@link 882 * EntityStore#close}.</p> 883 * 884 * @return the keys index. 885 */ 886 public synchronized EntityIndex<SK,PK> keysIndex() 887 throws DatabaseException { 888 889 if (keysIndex == null) { 890 if (keysDb == null) { 891 DatabaseConfig config = secDb.getConfig(); 892 config.setReadOnly(true); 893 config.setAllowCreate(false); 894 config.setExclusiveCreate(false); 895 try { 896 keysDb = DbCompat.openDatabase 897 (db.getEnvironment(), null/*txn*/, 898 DbCompat.getDatabaseFile(secDb), 899 secDb.getDatabaseName(), 900 config); 901 } catch (FileNotFoundException e) { 902 throw new DatabaseException(e); 903 } 904 } 905 keysIndex = new KeysIndex<SK,PK> 906 (keysDb, keyClass, keyBinding, 907 priIndex.getKeyClass(), priIndex.getKeyBinding()); 908 } 909 return keysIndex; 910 } 911 912 /** 913 * Returns an index that maps primary key to entity for the subset of 914 * entities having a given secondary key (duplicates). A sub-index is 915 * convenient when you are interested in working with the subset of 916 * entities having a particular secondary key value. 917 * 918 * <p>When using a {@link Relationship#MANY_TO_ONE MANY_TO_ONE} or {@link 919 * Relationship#MANY_TO_MANY MANY_TO_MANY} secondary key, the sub-index 920 * represents the left (MANY) side of a relationship.</p> 921 * 922 * @param key the secondary key that identifies the entities in the 923 * sub-index. 924 * 925 * @return the sub-index. 926 */ 927 public EntityIndex<PK,E> subIndex(SK key) 928 throws DatabaseException { 929 930 return new SubIndex(this, entityBinding, key); 931 } 932 933 /* 934 * Of the EntityIndex methods only get()/map()/sortedMap() are implemented 935 * here. All other methods are implemented by BasicIndex. 936 */ 937 938 public E get(SK key) 939 throws DatabaseException { 940 941 return get(null, key, null); 942 } 943 944 public E get(Transaction txn, SK key, LockMode lockMode) 945 throws DatabaseException { 946 947 DatabaseEntry keyEntry = new DatabaseEntry(); 948 DatabaseEntry pkeyEntry = new DatabaseEntry(); 949 DatabaseEntry dataEntry = new DatabaseEntry(); 950 keyBinding.objectToEntry(key, keyEntry); 951 952 OperationStatus status = 953 secDb.get(txn, keyEntry, pkeyEntry, dataEntry, lockMode); 954 955 if (status == OperationStatus.SUCCESS) { 956 return (E) entityBinding.entryToObject(pkeyEntry, dataEntry); 957 } else { 958 return null; 959 } 960 } 961 962 public Map<SK,E> map() { 963 return sortedMap(); 964 } 965 966 public synchronized SortedMap<SK,E> sortedMap() { 967 if (map == null) { 968 map = new StoredSortedMap(db, keyBinding, entityBinding, true); 969 } 970 return map; 971 } 972 973 boolean isUpdateAllowed() { 974 return false; 975 } 976} 977