Beispiel 1 – One-To-Many Relation

Der Anwendungsfall “Kunde hat mehrere Bestellungen” kann durch zwei Geschäftsobjekte Customer und Order modelliert werden. Durch Nutzung der Source-Level Annotationen wird die Beziehung zwischen den Instanzen, wie bei JPA üblich deklarativ beschrieben.

@SeifeClass(
        generatorOptions = {
                GeneratorOption.BOCLASS, GeneratorOption.SCHEMA_PEER,
                GeneratorOption.DB_HELPER+"=com.uc_mobileapps.seifesample01.db.CustomerDB",
                GeneratorOption.DATA_PROVIDER+"=com.uc_mobileapps.seifesample01.provider.CustomerProvider"
        },
        description = "A customer object, since this is a source annotation it won't occur in " +
        "the final class and has no runtime dependencies")
public class Customer {

    @SeifeField(isPrimaryKey = true,
        description="a simple primary key field")
    private Long id;

    @SeifeField
    private String name;

}

Mit @SeifeClassund @SeifeField wird festgelegt, dass für die Klasse zusätzlicher Programmcode generiert werden soll und welche Felder vom Code-Generator berücksichtigt werden. In den generatorOptions wählt man die benötigten Android-Code Typen.

@SeifeClass(
        generatorOptions = {
        GeneratorOption.BOCLASS, GeneratorOption.SCHEMA_PEER},
        description="Defines a simple many to one relation")
public class Order {
    @SeifeField(isPrimaryKey = true)
    private Long id;

    @SeifeField(mandatory = true, sqlOptions = @SqlFieldOptions(sqlIndex = "idxOrderDate"))
    private Date orderDate;

  /**
   * The foreign key field 'fkField' refers to {@link #customer},
   * it will be set via {@link #setCustomer(Customer)}.
   */
    @SeifeField(foreignKey = @ForeignkeyDef(fkField = "customer", refKeyField="id", refClass=Customer.class))
    private Long customerId;

  private Customer customer;

  public Customer getCustomer() {
    return customer;
  }
}

Ein Fremdschlüssel lässt sich direkt am Feld definieren, das Metamodell wird von dem Toolset um den benötigten Android Programmcode ergänzt und erspart die fehleranfällige und zeitaufwändige Entwicklung der benötigten Schnittstellen. Sämtliche Tabellen Eigenschaften sind als statische Bezeichner verfügbar und ermöglichen ein besseres Refactoring der Quelltexte als bei hart kodierter Schreibweise.

Es folgen die aus dem obigen Code generierten SQL Schema Peer Klassen mit üblicher Logik zum Lesen und Schreiben über die android.database.Cursor API.

Die Peer-Klassen enthalten auch die SQLite DDL Definitionen mit den benötigten Datentypen zur Anlage der Tabellen.

  • package com.uc_mobileapps.seifesample01.bo.schema;
    
    import com.uc_mobileapps.seifesample01.bo.Customer;
    
    import android.content.ContentResolver;
    import android.content.ContentValues;
    import android.content.Context;
    import android.database.Cursor;
    import android.net.Uri;
    import java.util.List;
    import java.util.ArrayList;
    
    public class CustomerSchema { 
      //[begin seife autogenerated@
    
      /**
       * Table name of the Customer table
       */
      public static String TBL_CUSTOMER = "customer";
      
    
      /** 
       * a simple primary key field
       */
      public static String COL_ID = "id";
    
      public static String COL_NAME = "name";
      
      /**
       * All columns
       */
      public static String[] COLUMNS = new String[] { COL_ID, COL_NAME	};
    
      /**
       * Table creation script
       */
      private static final String SQL_CREATE_TABLE_CUSTOMER =
          "create table " + TBL_CUSTOMER + " (" + 
    
              COL_ID + " integer primary key autoincrement," +
              COL_NAME + " text" +
              ")";
    
    
      private static CustomerSchema schema = new CustomerSchema();
      public static CustomerSchema instance() {
        return schema;
      }
    
      /**
       * Gets all attribute values of the bo as key value pairs
       * @param bo may not be null
       * @return new instance of {@link ContentValues}
       */
      public ContentValues getContentValues(Customer bo) {
        ContentValues contentValues = new ContentValues();
    
        if (bo.getId() != null) {
          contentValues.put(COL_ID, bo.getId());
        }
        contentValues.put(COL_NAME, bo.getName());
        return contentValues;
      }
    
      /**
       * Sets all attributes from the cursor
       * @param cursorFrom the cursor to read from
       * @param bo may be null
       * @return the bo passed as a parameter or a new instance
       */
      public Customer readFromCursor(Cursor cursorFrom, Customer bo)
      {
        if (bo == null) {
          bo = new Customer();
        }
        final Cursor c = cursorFrom; 
    
        bo.setId(c.isNull(c.getColumnIndex(COL_ID)) ? null : c.getLong(c.getColumnIndex(COL_ID)));
        bo.setName(c.getString(c.getColumnIndex(COL_NAME)));
        return bo;
      }
      
      /**
       * @return hard-coded table creation scripts
       */
      public List<String> getTableScripts() {
        List<String> result = new ArrayList<String>();
        result.add(SQL_CREATE_TABLE_CUSTOMER); 
        return result;
      }
      //@end seife autogenerated]
    }
    

  • package com.uc_mobileapps.seifesample01.bo.schema;
    
    import com.uc_mobileapps.seifesample01.bo.Order;
    
    import android.content.ContentResolver;
    import android.content.ContentValues;
    import android.content.Context;
    import android.database.Cursor;
    import android.net.Uri;
    import java.util.List;
    import java.util.ArrayList;
    
    import com.uc_mobileapps.seifesample01.bo.Customer;
    import com.uc_mobileapps.seifesample01.bo.schema.OrderSchema;
    import java.util.Date;
    
    public class OrderSchema { 
      //[begin seife autogenerated@
    
      /**
       * Table name of the Order table
       */
      public static String TBL_ORDER = "order";
      
    
      public static String COL_ID = "id";
    
      public static String COL_FK_CUSTOMER_CUSTOMER_ID = "customerId";
    
      public static String COL_ORDER_DATE = "orderDate";
      
      /**
       * All columns
       */
      public static String[] COLUMNS = new String[] { COL_ID, COL_FK_CUSTOMER_CUSTOMER_ID, COL_ORDER_DATE	};
    
      /**
       * Table creation script
       */
      private static final String SQL_CREATE_TABLE_ORDER =
          "create table " + TBL_ORDER + " (" + 
    
              COL_ID + " integer primary key autoincrement," +
              COL_FK_CUSTOMER_CUSTOMER_ID + " integer," +
              COL_ORDER_DATE + " integer not null" +
              ", " +
              " FOREIGN KEY(" + COL_FK_CUSTOMER_CUSTOMER_ID  + ")" +
              " REFERENCES " + CustomerSchema.TBL_CUSTOMER 
              +"(" + CustomerSchema.COL_ID  + ")" +			 		
              ")";
    
    
      private static OrderSchema schema = new OrderSchema();
      public static OrderSchema instance() {
        return schema;
      }
    
      /**
       * Checks for constraints defined on the fields
       */
      public boolean checkConstraints(ContentValues values) {
        //text,scancode,meta
        return true;
      }
      
      /**
       * Gets all attribute values of the bo as key value pairs
       * @param bo may not be null
       * @return new instance of {@link ContentValues}
       */
      public ContentValues getContentValues(Order bo) {
        ContentValues contentValues = new ContentValues();
    
        if (bo.getId() != null) {
          contentValues.put(COL_ID, bo.getId());
        }
        contentValues.put(COL_FK_CUSTOMER_CUSTOMER_ID, bo.getCustomerId());
        contentValues.put(COL_ORDER_DATE, (bo.getOrderDate()!=null) ? bo.getOrderDate().getTime() : null);
        return contentValues;
      }
    
      /**
       * Sets all attributes from the cursor
       * @param cursorFrom the cursor to read from
       * @param bo may be null
       * @return the bo passed as a parameter or a new instance
       */
      public Order readFromCursor(Cursor cursorFrom, Order bo)
      {
        if (bo == null) {
          bo = new Order();
        }
        final Cursor c = cursorFrom; 
    
        bo.setId(c.isNull(c.getColumnIndex(COL_ID)) ? null : c.getLong(c.getColumnIndex(COL_ID)));
        bo.setCustomerId(c.isNull(c.getColumnIndex(COL_FK_CUSTOMER_CUSTOMER_ID)) ? null : c.getLong(c.getColumnIndex(COL_FK_CUSTOMER_CUSTOMER_ID)));
        bo.setOrderDate(c.isNull(c.getColumnIndex(COL_ORDER_DATE)) ? null : new java.util.Date(c.getLong(c.getColumnIndex(COL_ORDER_DATE))));
        return bo;
      }
      
      /**
       * @return hard-coded table creation scripts
       */
      public List<String> getTableScripts() {
        List<String> result = new ArrayList<String>();
        result.add(SQL_CREATE_TABLE_ORDER); 
        return result;
      }
    
      /** 
       * Resolves the Customer instance for the Order#customer field
       * @param context the ContentResolver is obtained from there
       * @param bo the business object to get the foreign key reference from
       * @return
       */
      public Customer resolveCustomerField(Context context, Order bo) {
        ContentResolver contentResolver = context.getContentResolver();
        String selection = null;
        String[] selectionArgs = null;
    
        Uri uri = com.uc_mobileapps.seifesample01.provider.CustomerProvider.getContentUriCustomer().buildUpon()
            .appendQueryParameter(CustomerSchema.COL_ID, String.valueOf(bo.getId()))
            .build();
        Cursor cursor = contentResolver.query(uri, CustomerSchema.COLUMNS, selection, selectionArgs, null);
        try {
          Customer foreignInstance = 
              CustomerSchema.instance().readFromCursor(cursor, new Customer());
          //bo.setCustomer(foreignInstance);
          return foreignInstance;
        } finally {
          cursor.close();
        }
      }
      //@end seife autogenerated]	
    }