📜 ⬆️ ⬇️

Writing your Orm for Android with Canas and Senorites, Part 2

Introduction


Some community interest in my first article made me work hard on orm . I still don't like everything in it (somewhere the code is not optimized; somewhere the implementation is not the same as I wanted; there are not enough checks and perhaps stability), but it performs all the functions I need at the current moment. And so, meet: UcaOrm !

Using


We will consider working with orm on the example of the following model (more on the model in the 1st part ):
public class BaseEntity extends OrmEntity { @Column(primaryKey = true, inherited = true) private Long id; } @Table(name = "car_type", cashedList = true) public class CarType extends BaseEntity { @Column private String code; } @Table(rightJoinTo = {Truck.class}) public class Car extends BaseEntity { @Column(name = "car_type") private CarType type; @Column private List<Wheel> wheels; @Column(name = "engine_power") private int enginePower; @Column(name = "doors_count") private int doorsCount; } @Table public class Wheel extends BaseEntity { @Column(name = "car_id") private Car car; @Column private String manufacturer; } @Table(leftJoinTo = Car.class) public class Truck extends Car { @Column(name = "is_tipper") private boolean isTipper; } 

Customization

After adding the library to the project (in the future I plan to upload the compiled jar , but for now you can build it yourself from the sources), you need to create a Helper inherited from OrmHelper :
 public class DataBaseHelper extends OrmHelper { public DataBaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version); } @Override protected void onCreate() { } @Override protected void onUpgrade(int oldVersion, int newVersion) { } @Override public void getDefaultValues(Class<? extends OrmEntity> entityClass, ArrayList<String> columns, ArrayList<ContentValues> valueList) { } } 


The getDefaultValues method allows adding initial data to created tables. Its implementation is not yet very convenient, and in the future it will undergo processing.
Now we need to register a helper . This is done through the heir Application :
 public class MyApp extends Application { @Override public void onCreate() { super.onCreate(); try { OrmFactory.SetHelper(DataBaseHelper.class, getApplicationContext()); } catch (Exception e) { e.printStackTrace(); } } @Override public void onTerminate() { OrmFactory.ReleaseHelper(); super.onTerminate(); } } 

')
By default, the base name is formed from the Label application, and the version will be 1st. To change this, add the following lines to manifest :
 <meta-data android:name="UO_DB_NAME" android:value="Cars" /> <meta-data android:name="UO_DB_VERSION" android:value="1" /> 

Creating tables

The tables are created in the onCreate method, and the update in the onUpdate method, but the update is not yet supported in orm .
And so, create the necessary tables:
 protected void onCreate() { try { OrmUtils.CreateTable(CarType.class); OrmUtils.CreateTable(Car.class); OrmUtils.CreateTable(Wheel.class); OrmUtils.CreateTable(Truck.class); } catch (Exception e) { e.printStackTrace(); } } 

And fill in the CarType table with the initial data:
 public void getDefaultValues(Class<? extends OrmEntity> entityClass, ArrayList<String> columns, ArrayList<ContentValues> valueList) { ContentValues values; if (entityClass.equals(CarType.class)) { values = new ContentValues(); values.put(columns.get(0), "Passenger"); valueList.add(values); values = new ContentValues(); values.put(columns.get(0), "Truck"); valueList.add(values); } } 

As already said, the implementation of getDefaultValues ​​is lame.

Simple sampling

Since we have already filled the CarType table with data, I suggest first to consider a simple sample, and then creating instances and a sample from Where .
Let's create a copy of the type " passenger car ". To do this we first need to get all the types available to us. Since all entities that orm works with must inherit from OrmEntity , we will use its static getAllEntities methods. For beauty, we can block it in the class CarType :
 public static List<CarType> getAllCarTypes(){ try { return OrmEntity.getAllEntities(CarType.class); } catch (Exception e) { e.printStackTrace(); } return null; } 

Entity creation

Create an instance of Car:
  Car car = new Car(); car.setType(CarType. getAllCarTypes().get(0)); car.setEnginePower(116); car.setDoorsCount(4); Wheel whell = new Whell(); whell.setCar(car); whell.setManufacturer("Michrelli"); car.addWheel(whell); 

Of course, whell.setCar is better to pull inside addWheel like whell.setCar (this) , but I’ll give it here for clarity.
And just pull the alter method:
  car.alter(); 

Change the instance a bit:
  car.setEnginePower(120); car.getWheels().get(0).setManufacturer("Pirlin"); 


And just call again, alter :
  car.alter(); 

Now create a " truck ":

  Truck truck = new Truck(); truck.setType(CarType.getAllCarTypes().get(1)); truck.setEnginePower(220); truck.setDoorsCount(2); Wheel whell = new Whell(); whell.setCar(truck); whell.setManufacturer("Michrelli"); truck.addWheel(whell); truck.setTipper(true); truck.alter(); 

And the type of the variable is not important to us, we can declare it as Car , the main thing that lies in it.

Sample

We implement two methods in Car :
 public static List<Car> getAllCars() { try { return OrmEntity.getAllEntities(CarType.class, true); } catch (Exception e) { e.printStackTrace(); } return null; } public static List<Car> getCarsWithoutTrucks() { try { return OrmEntity.getAllEntities(CarType.class); } catch (Exception e) { e.printStackTrace(); } return null; } 

The difference is only in the getAllEntities call, however getAllCars returns two records, and getCarsWithoutTrucks only one: the second parameter indicates whether to select records associated with child tables, or only self-sufficient ones.
It is important to note the following: let's say we create a second instance with the type of Passenger . In the sample, since the CarType class is marked CashedList , both instances of Car will refer to the same instance of CarType .

Sampling with Where

Well, the most interesting!
OrmEntity has a static Where method that takes an entity class to fetch. For beauty, turn it off in Car :
  public static OrmWhere Where(){ return Where(Car.class); } 

And try to find cars with a power of 120 hp:

  List<Car> cars = Car.Where().Equals("engine_power", 120).Select(); 

Or cars with 120 hp and which has four doors:

  List<Car> cars = Car.Where().Equels(“engine_power”, 120).And().Equals("doors_count", 4).Select(); 

Or one of the cars that has a Pirlin wheel:

  Car car = Car.Where().FindChild(Wheel.class, new OrmWhere(Wheel.class).Equals("manufacturer", "Pirlin")).SelectFirst(); 

It is not yet possible to make a selection with inclusion from child tables (although orm supports it and, all that is needed is to add another Select method with the includeLeftChild parameter in OrmWhere ).

Conclusion


That's almost all what my orm is capable of so far . Now, the version number that I would assign to him is 0.1 . As I have already said, it implements everything that my application needs at the moment, and therefore such little things as, for example, Less or Great in OrmWhere are not yet implemented. The ability to update or delete tables is not implemented (although you can add new ones through the same CreateTable ). Because of the left and right join tables, we had to abandon calling query with parameters and pull rawQuery from SQLiteDatabase , as well as the cost of selecting all cached list entries increased from O (nk) (where n is the number of all records in the table, and k - number of already selected records) to O (n) . The types currently supported are: Int , Long , Double , Date , String , Drawable, and Document .
Perhaps I forgot to mention something, but in any case I will be happy with any questions and, especially, with the proposals for the development of UcaOrm .

Source: https://habr.com/ru/post/187526/


All Articles