LoginSignup
4
3

More than 5 years have passed since last update.

GAE/JにおけるDatastoreServiceアクセスの考察

Last updated at Posted at 2015-04-25

Who

Google App Engine (GAE/J)
App Engine SDK 1.9.18
JRE 1.7.0

What

DatastoreServiceへのアクセス方法を考える。

When, Where

サーバーサイド
DatastoreServiceへのアクセス部分

Why

一つ一つのEntityに対してDatastoreへのアクセスを書くのは面倒臭い。
また、見通しが悪くなる。
処理を共通化できるのであれば共通化する。

How

Person(名字、名前、身長)をDatastoreに保存する。
Personクラスを用意する。

Person.java
public final class Person implements Storable<Person> {
  static final String FIRST_NAME = "firstName";
  static final String LAST_NAME = "lastName";
  static final String HEIGHT = "height";
  private final String firstName;
  private final String lastName;
  private final int height;

  public Person(final String firstName, final String lastName, final int height) {
    super();
    this.firstName = firstName;
    this.lastName = lastName;
    this.height = height;
  }

  public final String getFirstName() {
    return firstName;
  }

  public final String getLastName() {
    return lastName;
  }

  public final int getHeight() {
    return height;
  }

  @Override
  public Map<String, Object> getPropertyMap() {
    return new HashMap<String, Object>() {
      private static final long serialVersionUID = 1L;
      {
        put(FIRST_NAME, getFirstName());
        put(LAST_NAME, getLastName());
        put(HEIGHT, getHeight());
      }
    };
  }

  @Override
  public Designable<Person> getDesign() {
    return new PersonDesign();
  }
}

必要なインターフェースはgetPropertyMapとgetDesign。
getPropertyMapはDatastoreに保存したい値とキー名のMapを返すようにする。

Designは以下のインターフェースを持つクラス。

PersonDesign.java
public class PersonDesign implements Designable<Person> {
  @Override
  public Person create(final Map<String, Object> propertyMap) throws IllegalPropertyMapException {
    for (final String propertyName : getPropertyNames()) {
      if (!propertyMap.containsKey(propertyName)) {
        throw new IllegalPropertyMapException();
      }
    }
    final String firstName = (String) propertyMap.get(Person.FIRST_NAME);
    final String lastName = (String) propertyMap.get(Person.LAST_NAME);
    final long height = (long) propertyMap.get(Person.HEIGHT);
    return new Person(firstName, lastName, (int) height);
  }

  @Override
  public String getName() {
    return "Person";
  }

  @Override
  public List<String> getPropertyNames() {
    return Arrays.asList(Person.FIRST_NAME, Person.LAST_NAME, Person.HEIGHT);
  }
}

createはPersonをnewするための関数。
getNameはKindNameを返す。
getPropertyNamesはPersonが保存するプロパティのキー名を返す。

DatastoreServiceへのアクセスは以下のDaoを通して行う。

CoreDao.java
public class CoreDao {
  private static final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

  public final <T extends Storable<T>> void put(final T input) {
    datastore.put(createEntity(input));
  }

  public final <T extends Storable<T>> void put(final Iterable<T> inputCollection) {
    final List<Entity> entityList = new ArrayList<Entity>();
    for (final T input : inputCollection) {
      entityList.add(createEntity(input));
    }
    datastore.put(entityList);
  }

  public final <T> Iterable<T> get(final Designable<T> design) {
    final Query q = new Query(design.getName());
    final PreparedQuery pq = datastore.prepare(q);
    final List<T> list = new ArrayList<T>();
    for (final Entity entity : pq.asIterable()) {
      final Map<String, Object> propertyMap = new HashMap<String, Object>();
      for (final String propertyName : design.getPropertyNames()) {
        propertyMap.put(propertyName, entity.getProperty(propertyName));
      }
      try {
        list.add(design.create(propertyMap));
      } catch (final IllegalPropertyMapException e) {
        e.printStackTrace();
      }
    }
    return list;
  }

  private <T extends Storable<T>> Entity createEntity(final T input) {
    assert input != null;

    final Entity entity = new Entity(input.getDesign().getName());
    for (final Entry<String, Object> entry : input.getPropertyMap().entrySet()) {
      final String propertyName = entry.getKey();
      final Object propertyValue = entry.getValue();
      entity.setProperty(propertyName, propertyValue);
    }
    return entity;
  }
}

Datastoreへの保存はputを用いる。
Entityクラスの作成はcreateEntityを使用する。
DesignのgetNameでKind名を取得。
StorableインターフェースのgetPropertyMapで保存するプロパティをセットする。

Datastoreからの取得はgetを用いる。
getの引数にはDesignクラスを渡す。
DesignのcreateでPersonインスタンスを作る。
CoreDaoにはPersonクラスに依存した処理はないので、インターフェースを実装したクラスであれば共通に使うことができる。

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3