Статьи

GuiceyData Generator быстро обрабатывает данные в MongoDB из Java

Одна из лучших сторон MongoDB — отсутствие принудительной схемы для коллекций. Такая гибкость дает разработчикам большую власть в том, как они работают со своими данными. Внедрение записей и массивов в другие записи допускает сложность и простоту организации данных, о которой СУБД могут только мечтать! Все это говорит о том, что работа с этими записями на языке, подобном Java, и в больших разнообразных группах людей, которые не хотят открывать базу данных и проверять записи, чтобы увидеть, какие значения и подзаписи доступны, означает, что вы будете всегда тратьте время на обертывание этих записей в строгом классе. Объединение свободных данных в классы, которые могут как обращаться, так и создавать эти данные, звучит так же, как другой проект, который я недавно использовал. Если вы не слышали о буферах протокола GoogleВозможно, вы захотите познакомиться.

Так как мне очень понравилось работать с Protocol Buffers, я подумал, что могу имитировать их функциональность и простоту использования с MongoDB. Это также прекрасно сочеталось бы с проектом GuiceyMongo, который я выпустил месяц или два назад.

Что такое генератор GuiceyData?

Генератор GuiceyData — это быстрый и простой способ указать строго типизированные структуры данных, которые будут храниться в базе данных MongoDB и отображаться в оболочках и компоновщиках в Java. Полученные классы являются строго данными и имеют (по замыслу) очень ограниченную функциональность. Их цель — сделать чтение и хранение данных в MongoDB легким делом с Java.

Как это работает?

Это довольно просто. Вы создаете файл определения данных, а затем запускаете генератор. Это создаст оболочки и компоновщики для всех определенных вами типов. Вот очень простой пример:

simple.data

data Person {
	string name;
	set<string> alias;
	blob picture;
}

Затем вы можете запустить генератор:

$ java -cp guiceymongogenerator-0.1.0.jar
com.lowereast.guiceymongo.data.generator.GuiceyDataGenerator -p test.data -s src

Это создаст структуру каталогов и файлы ниже:

+ src
  + test
    + data
      - Person.java

Упаковщики

После того как вы сгенерировали код, вы можете сделать что-то вроде этого:

Person p = Person.wrap(personCollection.findOne());
if (p.hasName())
    log.trace(p.getName());
if (p.getAliasCount() > 0)
    log.trace(StringUtil.join(p.getAliasSet(), ", "));
if (p.hasPicture()) {
    Image picture = ImageIO.read(p.getPictureInputStream());
    // do something with the picture
}

Обратите внимание, что в приведенном выше примере BLOB-объекты будут работать только в том случае, если вы используете GuiceyMongo для настройки своих баз данных, коллекций и сегментов. Используя GuiceyMongo, мы также можем просто сделать это:

@Inject
void loadPerson(@GuiceyMongoCollection("person")
    GuiceyCollection<Person> personCollection) {
    Person p = personCollection.findOne();
    // ...
}

 

Строители

Какая польза от возможности читать данные, если мы не можем их создать? Для этого есть строители:

Person.Builder p = Person.newBuilder()
                .setName("Matt Insler")
                .addAlias("Matt")
                .addAlias("Guice & Mongo Guru")
                .setPictureBucket("pictures");
ImageIO.write(picture, format, p.getPictureOutputStream());
personCollection.save(p.build());

И еще раз с GuiceyMongo:

@Inject
void loadPerson(@GuiceyMongoCollection("person")
    GuiceyCollection<Person> personCollection) {
    Person p = Person.newBuilder() // ...
    personCollection.save(p);
}

Это действительно так просто!

Строитель Прототипы

Вы можете создавать строителей на основе другого объекта. Это может быть обертка или сам строитель. Это полезно, когда вы хотите использовать прототип объекта или просто скопировать объект, который вы только что прочитали.

Person p = Person.wrap(collection.findOne());
Person newPerson = Person.newBuilder(p);

 

Более сложный

Вот пример более сложного файла определения данных, который показывает вам больше того, что может обработать генератор:

Контактные данные

data Contact {
	data Address {
		string street_1;
		string street_2;
		string city;
		string state;
		int zip_code;
	}

	[identity]
	string identity;

	string first_name;
	string last_name;
	map<string, Address> address;
	map<string, string> phone_number;
	map<string, string> email_address;
	map<string, InstantMessenger> instant_messenger;
	set<string> tag;
	blob picture;
}

data InstantMessenger {
	enum Application {
		AIM,
		ICQ,
		Jabber,
		MSN,
		Yahoo
	}

	string screen_name;
	string alias;
	IMApplication application;
}

Интеграция с GuiceyMongo хранимой процедурой Proxies

Теперь, когда вы сгенерировали код для доступа и создания своих данных, что, если вы хотите вернуть эти данные из хранимой процедуры? Это довольно просто!

public interface ContactQuery {
    Contact findContactByName(String name);
    List<Contact> findContactsByIMAlias(String alias);
}
 
@Inject
void exercise(ContactQuery query) {
    query.findContactByName("Matt Insler");
}

Не так уж плохо, правда?

Типы данных пользователя

data [name] {
	[type] [property name];
	...
	OtherData.Embedded [property name];
	data [embedded type name] {
		[type] [property name];
		...
	}
}

Типы перечислений пользователей

enum [name] {
	[value],
	...
	[value]
}


Примечание по типам перечислений:
Пользовательские типы перечислений будут храниться в MongoDB как [enum value] .name (). Преобразования будут сделаны при чтении и хранении этих значений. Будьте очень, очень осторожны при изменении значений перечисления. Их также необходимо изменить в базе данных.

Параметры

В настоящее время есть только один доступный вариант. Это вариант идентификации. Параметры указываются непосредственно над свойством, к которому они должны применяться, и заключаются в квадратные скобки.

data Foo {
	[identity]
	string identity;
}
data Bar {
	[identity]
	object_id identity;
}

Опция identity указывает, что это свойство должно быть прочитано и сохранено как ObjectId и использовано в качестве значения _id. Сгенерированный код будет выполнять автоматическое преобразование между ObjectId и String, если тип свойства — строка.

Почему бы не делать то, что делают другие?

В двух словах, личные предпочтения. Хотя я думаю, что другие доступные библиотеки имеют свое место, у меня есть определенные предпочтения, которые привели меня к разработке GuiceyData так, как я это сделал.

GuiceyData против Морфия

Morphia — это библиотека стилей JPA, которая позволяет аннотировать POJO, а затем преобразовывать их в объекты DBObject и из них. Это довольно неплохо и поддерживает множество функций, таких как запросы строгих типов, генерация DAO / Datastore, встроенные и ссылочные объекты данных и многое другое. Это определенно стоит проверить и может быть подходящей библиотекой для вас.

Основным положительным моментом в морфии является способность сохранять POJO, которые вы уже создали и использовали. Просто аннотируйте поля и уходите! Что мне не нравится, так это то, что мне не нравится иметь дело с полным преобразованием объектов. Код не так быстр и эффективен, как мог бы, потому что он должен использовать отражение и должен обрабатывать все поля объекта независимо от того, какие поля фактически используются в вашем коде. Кроме того, с базой данных без схемы, такой как mongo, вы не можете гарантировать, что все значения в POJO будут заполнены при преобразовании объекта, поэтому вы не можете использовать примитивные типы, так как они не допускают обнуления. Другая проблема, с которой я столкнулся, заключается в том, что мне действительно очень не нравится создавать собственные хранилища данных и отсутствие внешнего контроля над тем, какие базы данных и коллекции используются.С GuiceyMongo я могу создавать обертки объектов, которые будут лениво обращаться к данным с помощью кода, написанного специально для объекта, с которым я имею дело. Никаких размышлений и отложенной загрузки и обработки == очень быстро! GuiceyMongo также отделяет спецификацию данных от кода Java. Это очень полезно, когда вы хотите совместно использовать объекты в организации, которая использует разные языки для доступа к базе данных. Все языки могут быть сгенерированы из одной спецификации. По моему мнению (понимаете, что я создатель GuiceyMongo), GuiceyMongo добивается большего, чем морфия, более чистым способом и быстрее.Это очень полезно, когда вы хотите совместно использовать объекты в организации, которая использует разные языки для доступа к базе данных. Все языки могут быть сгенерированы из одной спецификации. По моему мнению (понимаете, что я создатель GuiceyMongo), GuiceyMongo добивается большего, чем морфия, более чистым способом и быстрее.Это очень полезно, когда вы хотите совместно использовать объекты в организации, которая использует разные языки для доступа к базе данных. Все языки могут быть сгенерированы из одной спецификации. По моему мнению (понимаете, что я создатель GuiceyMongo), GuiceyMongo добивается большего, чем морфия, более чистым способом и быстрее.

GuiceyData vs. Sculptor

Sculptor — это генератор кода, который был адаптирован для создания кода преобразования MongoDB. Он следует идее Rails, создавая множество методов и классов, чтобы помочь вам справиться с вашими классами данных. Немного сложно понять, что именно происходит, но вы можете понять все это, немного поиграв с ним. Как и Morphia, Sculptor преобразует ваши объекты данных в DBObjects и из них. В отличие от morphia, Sculptor генерирует этот код преобразования, который делает его быстрее, так как нет отражения. Что мне действительно нравится в Sculptor, так это язык запросов, который он предоставляет. Это гораздо более простой способ запроса сгенерированных объектов, чем создание объектов DBObject вручную или даже использование QueryBuilder в пакете com.mongodb. Эта функциональность побудила меня начать создавать собственный DSL-запрос, который я надеюсь выпустить в следующем месяце. Проверьте это!

Теперь для критики. Моя главная и самая большая критика Скульптора в том, что он настолько гибкий, что становится сложным. Я большой сторонник того, чтобы ваши объекты данных были просто … объектами данных. Я не вижу очень убедительного сценария использования классов скаффолдинга, которые наследуются от ваших классов данных и исключают дополнительную функциональность. Если вы хотите этот функционал, напишите его, но не включайте в определение данных. То же самое касается хранилищ. Они действительно не так сильно тебя покупают. Зачем вам нужно генерировать общие методы для каждого типа репозитория? Разве это не для чего дженерики? Все базовые классы репозитория будут идентичны, за исключением методов, которые вы к ним добавляете. Строительные леса это хорошо, но не обязательно. Я также думаю, что генерация конверсий немного близорука. Если вы генерируете код,почему бы не генерировать ленивую загрузку в ваших объектах данных? Я понимаю, что людям нравятся POJO, но они очень медленные. Мы имеем дело с базами данных здесь. Узким местом должно быть запросы и обработка данных, а не построение объектов вокруг данных, которые вы получили или храните. Мой последний недостаток — то, что я решил не поддерживать в GuiceyMongo из-за того, что MongoDB не содержит схем. Скульптор поддерживает наследование объектов. Это хорошая функция, но я не уверен, что это абсолютно необходимо. Объект в MongoDB может быть разных типов, объединенных в один. Я могу создать объект электронной почты, а затем наложить поверх него объект задачи. Я не хочу цепочку наследования для этого. Я хочу способ конвертировать один тип объекта в другой. Обертывание необработанных объектов DBO с помощью аксессоров — это очень чистый и быстрый способ сделать это.В GuiceyData все, что вам нужно сделать, это Email e = Email.wrap (…); Task t = Task.convertFrom (e); Типы данных затем могут храниться в базе данных в одном и том же объекте или в разных объектах или даже в разных коллекциях.

Использование предприятия

И GuiceyMongo, и GuiceyData были созданы с учетом использования на предприятии. GuiceyMongo позволяет создавать несколько конфигурационных сред, таких как Test, QA, Prod и т. Д., Где вы можете отобразить базы данных, коллекции и сегменты (GridFS) на любой сервер, базу данных или коллекцию, которую вы хотите. Просто изменив конфигурацию, ваши данные могут быть загружены или сохранены в другом месте. Если эта конфигурация абстрагируется в файл конфигурации или библиотеку конфигурации, она может быть общей для всего предприятия и при необходимости переопределена локально. Что касается генерации данных, файлы определений говорят только о данных. Это все, о чем они когда-либо будут говорить. Это означает, что код может быть сгенерирован на разных языках с легкостью. Если вы пишете библиотеку доступа к данным, которая будет распространяться среди других групп,вы можете использовать Google Guice, чтобы предоставить простой способ настройки библиотеки и упаковки сгенерированных классов данных. Нет необходимости заставлять пользователей генерировать код, просто используйте ваш jar или около того или dll.

Интеграция GuiceyMongo и GuiceyData позволит легко начать работу с MongoDB из Java. В будущем я напишу краткий пост о том, как быстро и легко все это может быть!

Попробуй!

Просто зайдите на страницу загрузки GitHub и возьмите банки 0,1.0. Для генерации ваших классов запустите генератор, как указано выше. Чтобы использовать GuiceyMongo, добавьте ссылку на него и его зависимости и посмотрите мои другие посты на эту тему.

зависимости

guiceydatagenerator- [версия] .jar Нет
guiceymongo- [версия] .jar aopalliance.jar (входит в состав Google Guice), guice-2.0.jar, mongo-1.4.jar (или более поздняя версия)

Как всегда, любые проблемы, с которыми вы сталкиваетесь, пожалуйста, свяжитесь со мной !

Источник: http://www.mattinsler.com/mongodb-java-dao-generator-guiceydata/