public void delete(OpenJPAStateManager sm, JDBCStore store, RowManager rm) throws SQLException {
    if (field.getMappedBy() != null) return;

    // if nullable, null any existing inverse columns that refer to this obj
    ValueMapping elem = field.getElementMapping();
    ColumnIO io = elem.getColumnIO();
    ForeignKey fk = elem.getForeignKey();
    if (!elem.getUseClassCriteria() && io.isAnyUpdatable(fk, true)) {
      assertInversable();
      Row row = rm.getAllRows(fk.getTable(), Row.ACTION_UPDATE);
      row.setForeignKey(fk, io, null);
      row.whereForeignKey(fk, sm);
      rm.flushAllRows(row);
      return;
    }

    if (!sm.getLoaded().get(field.getIndex())) return;

    // update fk on each field value row
    ClassMapping rel = field.getElementMapping().getTypeMapping();
    StoreContext ctx = store.getContext();
    Collection objs = toCollection(sm.fetchObject(field.getIndex()));
    if (objs != null && !objs.isEmpty())
      for (Iterator itr = objs.iterator(); itr.hasNext(); )
        updateInverse(ctx, itr.next(), rel, rm, sm, 0);
  }
  /** This method updates the inverse columns of a 1-M related object with the given oid. */
  private void updateInverse(
      StoreContext ctx,
      Object inverse,
      ClassMapping rel,
      RowManager rm,
      OpenJPAStateManager sm,
      int idx)
      throws SQLException {
    OpenJPAStateManager invsm = RelationStrategies.getStateManager(inverse, ctx);
    if (invsm == null) return;

    ValueMapping elem = field.getElementMapping();
    ForeignKey fk = elem.getForeignKey();
    ColumnIO io = elem.getColumnIO();
    Column order = field.getOrderColumn();

    int action;
    boolean writeable;
    boolean orderWriteable;
    if (invsm.isNew() && !invsm.isFlushed()) {
      // no need to null inverse columns of new instance
      if (sm == null || sm.isDeleted()) return;
      writeable = io.isAnyInsertable(fk, false);
      orderWriteable = _orderInsert;
      action = Row.ACTION_INSERT;
    } else if (invsm.isDeleted()) {
      // no need to null inverse columns of deleted instance
      if (invsm.isFlushed() || sm == null || !sm.isDeleted()) return;
      writeable = true;
      orderWriteable = false;
      action = Row.ACTION_DELETE;
    } else {
      if (sm != null && sm.isDeleted()) sm = null;
      writeable = io.isAnyUpdatable(fk, sm == null);
      orderWriteable = field.getOrderColumnIO().isUpdatable(order, sm == null);
      action = Row.ACTION_UPDATE;
    }
    if (!writeable && !orderWriteable) return;

    assertInversable();

    // if this is an update, this might be the only mod to the row, so
    // make sure the where condition is set
    Row row = rm.getRow(fk.getTable(), action, invsm, true);
    if (action == Row.ACTION_UPDATE) row.wherePrimaryKey(invsm);

    // update the inverse pointer with our oid value
    if (writeable) row.setForeignKey(fk, io, sm);
    if (orderWriteable) row.setInt(order, idx);
  }
  public void map(boolean adapt) {
    OpenJPAConfiguration conf = field.getRepository().getConfiguration();
    boolean isNonDefaultMappingAllowed =
        field.getRepository().getMetaDataFactory().getDefaults().isNonDefaultMappingAllowed(conf);
    FieldMapping mapped = field.getMappedByMapping();

    // JPA 2.0 allows non-default mapping: Uni-/1-M/@JoinColumn ==> foreign key strategy
    // Bi-/1-M/@JoinColumn should result in exception
    if (!isNonDefaultMappingAllowed || mapped != null) {
      field.getValueInfo().assertNoSchemaComponents(field, !adapt);
    }
    field.getKeyMapping().getValueInfo().assertNoSchemaComponents(field.getKey(), !adapt);

    ValueMapping elem = field.getElementMapping();
    if (elem.getTypeCode() != JavaTypes.PC
        || elem.isEmbeddedPC()
        || !elem.getTypeMapping().isMapped())
      throw new MetaDataException(_loc.get("not-elem-relation", field));

    // check for named inverse
    FieldMappingInfo finfo = field.getMappingInfo();
    ValueMappingInfo vinfo = elem.getValueInfo();
    boolean criteria = vinfo.getUseClassCriteria();
    if (mapped != null) {
      mapped.resolve(mapped.MODE_META | mapped.MODE_MAPPING);
      if (!(mapped.getStrategy() instanceof RelationFieldStrategy
          || mapped.getHandler() instanceof UntypedPCValueHandler))
        throw new MetaDataException(_loc.get("not-inv-relation", field, mapped));
      vinfo.assertNoSchemaComponents(elem, !adapt);
      elem.setForeignKey(mapped.getForeignKey(field.getDefiningMapping()));
      elem.setColumns(mapped.getDefiningMapping().getPrimaryKeyColumns());
      elem.setJoinDirection(ValueMapping.JOIN_EXPECTED_INVERSE);
      elem.setUseClassCriteria(criteria);

      ForeignKey fk = mapped.getForeignKey();
      /**
       * Foreign key may be null if declared type of the mapped field is abstract and under
       * table-per-class inheritance strategy will have no mapped table.
       */
      if (fk != null) {
        field.setOrderColumn(finfo.getOrderColumn(field, fk.getTable(), adapt));
        field.setOrderColumnIO(finfo.getColumnIO());
      }
      return;
    } else {
      if (field.getValueInfo().getColumns().size() > 0
          && field.getAccessType() == FieldMetaData.ONE_TO_MANY) {
        _uni1MFK = true;
      }
    }

    // map inverse foreign key in related table
    ForeignKey fk = vinfo.getInverseTypeJoin(elem, field.getName(), adapt);
    if (_uni1MFK) {
      Column[] locals = fk.getColumns();
      for (int i = 0; i < locals.length; i++) locals[i].setUni1MFK(true);
    }
    elem.setForeignKey(fk);
    elem.setColumnIO(vinfo.getColumnIO());
    elem.setColumns(elem.getTypeMapping().getPrimaryKeyColumns());
    elem.setJoinDirection(ValueMapping.JOIN_EXPECTED_INVERSE);
    elem.setUseClassCriteria(criteria);
    elem.mapConstraints(field.getName(), adapt);

    field.setOrderColumn(finfo.getOrderColumn(field, fk.getTable(), adapt));
    field.setOrderColumnIO(finfo.getColumnIO());
  }