آشنایی با دیتابیس مدرن ObjectBox

نویسنده : سید ایوب کوکبی ۲۸ آذر ۱۳۹۷
آشنایی با دیتابیس مدرن ObjectBox

ObjectBox یک ORM سبک وزن اندرویدی است. در گذشته حتی برای یک برنامۀ ساده، باید کوئری‌های SQL می‌نوشتیم. اکنون هم می‌توانیم از Sqlitehelper در پلتفرم اندروید برای نوشتن این کوئری‌ها استفاده کنیم ولی اغلب برنامه‌نویسان تمایل دارند با روش‌های ساده‌تری  به دیتابیس متصل شوند. برای رفع این نیاز راهکارهای مختلفی مطرح شد که ORM یا Object Relation Mapping مهم‌ترین راهکار در این زمینه بود.

با توجه محدودیت‌های حاکم در اندروید مسلماً باید دنبال ORM هایی باشیم که چه از لحاظ اجرایی و چه از لحاظ حجم، سبک باشند. باید موردی انتخاب کنیم که سرعت بالایی داشته باشد و منحنی یادگیری آن تا حد امکان راحت باشد. مثلاً Hibernate گرچه ویژگی‌های زیادی دارد ولی به خاطر وجود وابستگی‌های فراوان اصلاً برای اپلیکیشن‌های اندرویدی مناسب نیست چون قطعاً روی حجم برنامه تأثیر بدی خواهد داشت، ضمن اینکه بسیاری از قابلیت‌های آن در اکوسیستم اندروید قابل استفاده نیست.

از بین گزینه‌های موجود، ObjectBox نسبت به بقیه سبک‌تر و مدرن‌تر است. این دیتابیس را همان افرادی ساخته‌اند که پیش‌تر greenDAO و EventBus را ساخته‌اند. اگر برنامه‌ای دارید که داده‌ها را باید به صورت لوکال ذخیره کند، آبجکت باکس انتخاب مناسبی است. تفاوت اصلی‌اش این است که به هیچ عنوان از اس کیو ال استفاده نمی‌کند. برنامه‌های معروفی مثل پینترست، اسنپ‌چت، رانتستیک، فروشگاه علی بابا و … از این دیتابیس استفاده کرده‌اند.

سایت آبجکت‌ باکس، دیتابیسش را اینگونه تعریف می‌کند:

ObjectBox یک دیتابیس فوق سریع بوده که منحصراً برای دستگاه‌های موبایلی و اینترنت اشیاء ساخته شده است. به راحتی می‌تواند داده‌ها را به صورت محلی و با سرعت و کارایی بالا در مکانی امن ذخیره و مدیریت کند. آبجکت باکس کمتر از ۱ مگابایت حجم دارد که برای اپلیکیشن‌های موبایل و اینترنت اشیاء ایده‌آل است. ما اولین دیتابیس NoSQL سازگار با ACID بر روی دستگاه‌های موبایلی هستیم. محصولات ما با در نظر گرفتن نیاز برنامه‌نویسان طوری ساخته شده‌اند که ضمن سادگی، پیاده‌سازی‌شان حداقل کد را نیاز داشته باشند.

مزایای ObjectBox

  • سرعت بالا: طبق بنچمارک‌های انجام شده، آبجکت باکس ۱۰ برابر سریع‌تر از SQLite است؛
  • حمایت گسترده از روابط: این دیتابیس می‌تواند تغییرات را دنبال کند، از انواع استراتژی‌های لودینگ مثل lazy loading و eager loading حمایت می‌کند؛
  • از زبان SQL استفاده نمی‌کند: بنابراین لازم نیست برای کار با دیتابیس زبان دیگری یاد بگیرید؛
  • API مدرن: آبجکت باکس APIهای ساده‌ای دارد و به طور کامل از RxJava2 حمایت می‌کند؛
  • کدهای تمییزتر برای موجودیت‌ها: ObjectBox بسیاری از کدها را در پس زمینه به صورت مخفی تولید می‌کند که این کار سورس کد شما را بسیار تمییز نشان می‌دهد؛
  • پشتیبانی از کاتلین: ObjectBox از زبان کاتلین و قابلیت data class آن پشتیبانی می‌کند؛
  • سینک خودکار و بدون دردسر داده‌ها؛
  • کراس پلتفرم: قابل استفاده در لینوکس، ویندوز، اندروید، مک، iOS، رزبری پای، ARM
  • حجم بسیار کم: کمتر از ۱ مگابایت، ایده‌آل برای دستگاه‌های موبایلی که منابع محدودی دارند؛
  • یادگیری آسان: چون نیازی به یادگیری SQL ندارد، یادگیری آن آسان است؛
  • اجرای آسان یونیت تست؛
  • سازگار با ACID و MVCC برای انجام تراکنش‌های امن؛
  • حمایت از چند نخی؛
  • و … .
بخوانید  کاهش حجم فایل‌های PNG

البته ذکر این نکته هم ضروری است که اگر برنامۀ شما وابستگی زیادی به SQL دارد و کوئری‌ها و ویوهای مختلفی برای آن نوشته‌اید،  کمی مهاجرت به این دیتابیس سخت خواهد شد چون نیازمند تغییرات گسترده‌ای در کدهایتان خواهید بود. در هر صورت توصیه می‌کنیم مستندات ObjectBox را بخوانید و بعد از تست قابلیت‌های آن در یک پروژۀ ساده‌تر اقدام به مهاجرت کنید. 

شروع کار

ابتدا طبق راهنما، گریدل را تنظیم کنید تا به این کتابخانه دسترسی کامل داشته باشید. همچون سابق کلاس‌های مدل خود را ایجاد کنید و انوتیشن Entity@ را پیش از نام کلاس قرار دهید. با این کار به ObjectBox می‌گویید که این کلاسی که نوشتم را به عنوان یک موجودیت یا Entity در نظر بگیر.

@Entity
public class Animal {
    @Id(assignable = true)
    private long id;

    private String name;

    private boolean flying;

    private boolean swimming;

    private boolean walking;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean isFlying() {
        return flying;
    }

    public void setFlying(boolean flying) {
        this.flying = flying;
    }

    public boolean isSwimming() {
        return swimming;
    }

    public void setSwimming(boolean swimming) {
        this.swimming = swimming;
    }

    public boolean isWalking() {
        return walking;
    }

    public void setWalking(boolean walking) {
        this.walking = walking;
    }
}

آبجکت باکس نیازمند دسترسی به پراپرتی‌های کلاس شماست. بنابراین برای تمام فیلدها از متدهای getter و setter استفاده کنید. همچنین می‌توانید مودیفایر private را حذف کنید تا آبجکت باکس خودش مستقیماً به آن‌ها دسترسی داشته باشد. 

پس از آماده شدن دیتا مدل باید دیتابیس را مقداردهی اولیه کنید. ترجیحاً این کار را می‌توانید در کلاس Application انجام دهید ولی به سلیقۀ خودتان می‌توانید از الگوی سینگلتون استفاده کنید یا از تزریق Dagger بهره ببرید. کلاس Application اکنون باید چنین وضعیتی داشته باشد:

public class App extends Application {

    private static App sApp;
    private BoxStore mBoxStore;

    @Override
    public void onCreate() {
        super.onCreate();
        sApp = this;
        mBoxStore = MyObjectBox.builder().androidContext(App.this).build();
    }

    public static App getApp() {
        return sApp;
    }

    public BoxStore getBoxStore() {
        return mBoxStore;
    }
}

عملیات CRUD

حالا می‌توانید با استفاده از کلاس BoxStore به دیتابیس دسترسی پیدا کنید. اینجا به جای استفاده از جداول SQL از box استفاده می‌کنید. به مثال زیر توجه کنید:

BoxStore boxStore = App.getApp().getBoxStore();
Box<Animal> animalBox = boxStore.boxFor(Animal.class);

// loads all animals
List<Animal> animals = animalBox.getAll();

// find a specific animal in the database
long myDogId = 12;
Animal myDog = animalBox.get(myDogId);

// insert an animal into the database
animalBox.put(newAnimal);

// update an animal
myDog.setSwimming(true);
animalBox.put(myDog);

//query for all the flying animals
List<Animal> flyingAnimals = animalBox.query().equal(Animal_.isFlying, true).build().find();

//delete all flying animals from the database
animalBox.remove(flyingAnimals);

این فقط یک عملیات سادۀ CRUD است. شما می‌توانید کوئری‌های بسیار پیچیده‌تری هم بنویسید؛ آن هم بدون درگیر شدن با دستورات گیج‌کنندۀ SQL. در ObjectBox، کوئری‌ها در ساده‌ترین شکل ممکن نوشته می‌شوند. بنابراین ارتباط زنجیروار آن‌ها به سادگی قابل درک است. برای آشنایی بیشتر با نوشتن کوئری‌ها به مستندات دیتابیس مراجعه کنید.

بخوانید  آشنایی با معماری Clean Architecture در برنامه‌نویسی اندروید

روابط

همچون بسیاری از دیتابیس‌ها، آبجکت باکس نیز از روابط بین موجودیت‌ها یا relation ها پشتیبانی می‌کند. اینجا می‌توانید از روابط یک به یک، یک به چند و چند به چند استفاده کنید. به عنوان مثال، نمونه‌ای از روابط یک به چند را در کد پایین می‌بینید:

@Entity
public class Zoo {

    @Id
    private long id;


    // a Zoo can have many Animals
    @Backlink
    ToMany<Animal> animals;
  
    ...
}

@Entity
public class Animal {
    @Id(assignable = true)
    private long id;

    private String name;

    private boolean flying;

    private boolean swimming;

    private boolean walking;

    // an Animal belongs to one Zoo
    ToOne<Zoo> zoo;
  
    ...
}

کد بالا رابطۀ یک به چندی بین Zoo یعنی باغ وحش و Animals یعنی حیوانات برقرار می‌کند. همانطور که در دنیای واقعی هم شاهدش هستیم، رابطۀ بین باغ وحش و حیوانات آن رابطه‌ای یک به چند است. داخل هر باغ وحش حیونات مختلفی وجود دارد. برای اصلاح روابط یا دسترسی به آن‌ها می‌توانید اینطور عمل کنید:

Zoo myZoo = new Zoo();

Animal elephant = new Animal();
Animal giraffe = new Animal();

// To-one relation: Set the Zoo that an animal belongs to and save it to the database
elephant.zoo.setTarget(myZoo);
animalBox.put(elephant);

// To-one relation: Get the Zoo that an animal belongs to
Zoo elephantZoo = elephant.zoo.getTarget();


// To-many relation: Add Animals to the Zoo and save it to the database
myZoo.animals.add(elephant);
myZoo.animals.add(giraffe);
zooBox.put(myZoo);

// To-many relation: Get Animals that belongs to a Zoo
List<Animal> zooAnimals = myZoo.animals;

مهاجرت

برخلاف سایر دیتابیس‌ها (از جمله greenDAO)، مهاجرت به این دیتابیس تقریباً به صورت خودکار انجام می‌گیرد. بنابراین لازم نیست نگران مدیریت نسخه‌های مختلف اسکیما باشید. مثلاً اگر پراپرتی جدیدی اضافه یا حذف کرده‌اید هیچ کدی برای مهاجرت نیاز نیست. تنها در دو حالت نگرانی وجود دارد. یک مورد تغییر نام کلاس‌ها و پراپرتی‌هاست و دیگری تغییر نوع پراپرتی‌ها. برای هندل کردن این حالات، توضیحاتی در مستندات آمده که بد نیست بخوانید. به جزء این دو مورد تقریباً هیچ چیز نگران‌کنندۀ دیگری برای بحث migration یا مهاجرت وجود ندارد.

بخوانید  بهترین روش نام‌گذاری ریسورسها در اندروید

جمع‌بندی

ObjectBox قابلیت‌های بسیار بیشتری همچون تراکنش‌ها، ایندکس‌ها، پشتیبانی از کاتلین، reactive extension و لیست‌ها دارد که ما در اینجا فقط به گوشه‌ای از آن اشاره کردیم. با پیشرفت خوب این کتابخانه  آیندۀ درخشانی برای آن انتظار داریم.

سید ایوب کوکبی

نویسنده و مترجم...

مطالب مرتبط

0 دیدگاه

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *