1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/wkgcass-DAF4J

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
Внести вклад в разработку кода
Синхронизировать код
Отмена
Подсказка: Поскольку Git не поддерживает пустые директории, создание директории приведёт к созданию пустого файла .keep.
Loading...
README.md

Фасад доступа к данным для Java (DAF4J)

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

  • Работает на Java 1.6 и более поздних версиях.
  • Для использования необходимо добавить в проект daf4j-api.jar и требуемую реализацию DataAccess.
  • DAF4j также предоставляет упрощённые операции для Scala.

Использование

Способ 1: Загрузите архив с сайта git@osc и добавьте его в свой проект, а также добавьте зависимости согласно инструкции (сам daf4j-api.jar не требует зависимостей, но реализация DataAccess требует, подробности приведены ниже).

Способ 2: Используйте Maven для добавления зависимостей.

<dependencies>
    <dependency>
        <groupId>net.cassite</groupId>
        <artifactId>daf4j-api</artifactId>
        <version>0.1.1-RELEASE</version>
    </dependency>
</dependencies>

Предварительный просмотр использования

Язык Стиль
Java Stream
query
    .from(user)
    .stream()
    .filter(user.age.$gt(18).and(user.name.$ne("cass")))
    .filter(role.name.$eq("admin"))
    .sorted(user.id.desc())
    .limit(10)
.list();

// Запрос пользователей старше 18 лет, с именем, отличным от «cass», и ролью администратора, отсортированных по идентификатору пользователя в порядке убывания и ограниченных первыми 10 записями.

| Scala | SQL |

query from user where user.age > 18 & user.name <> "cass" & role.name === "admin" param (orderBy(user.id.desc) top 10) list

// Функционал аналогичен предыдущему примеру.

Причины разработки этой библиотеки классов

DAF4J предназначен для упрощения доступа к данным. В трёхслойной архитектуре структура слоя данных во многом зависит от бизнес-логики. Часто бизнес-слой выполняет только некоторые проверки данных и преобразование типов данных, оставляя прямой вызов слою данных, а слой данных иногда может писать некоторые «специализированные» методы для бизнес-слоя.

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

Даже такие инструменты, как Spring Data JPA или JPA Criteria, имеют некоторые недостатки в обработке условий (например, меньше(поле, значение) вместо поле.меньше(значение)), и код немного более громоздкий.

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

После некоторого проектирования началась разработка.

Использование

Здесь представлен предварительный обзор, подробное использование можно найти на странице Wiki. Кроме того, на странице Wiki есть учебное пособие, демонстрирующее использование DAF4J в контексте простой модели RBAC.

Для использования необходимо импортировать daf4j-api.jar (или использовать Maven).

В этом примере используется реализация JPQLDataAccess из daf4j-ds-jpa.jar. Мы создадим класс сущности, внеся небольшие изменения в способ реализации DAF4J:

Я создал генераторы геттеров и сеттеров для IDEA, чтобы упростить генерацию JavaBean для DAF4J. Генераторы кода доступны в корне репозитория GetterGeneratorForIDEA.txt и SetterGeneratorForIDEA.txt.

@Entity
class User{
    public final XInt id = new XInt(this);
    public final XString name = new XString(this);
    public final XInt age = new XInt(this);
        
    @Id
    public Integer getId(){ return id.get(); }
    public String getName(){ return name.get(); }
    public Integer getAge(){ return age.get(); }
        
    public void setId(Integer id){ DataUtils.set(this.id, id); }
    public void setName(String name){ DataUtils.set(this.name, name); }
    public void setAge(Integer age){ DataUtils.set(this.age, age); }
}

Чтобы использовать функции JPA, вам также потребуется получить EntityManager, а затем использовать его для инициализации JPQLDataAccess и Query.

Query query=new Query(new JPQLDataAccess(entityManager));

Затем вы можете начать использовать:

User user=new User();
    
// Список всех пользователей старше 18 лет
query
    .from(user)
    .where(user.age.$gt(18))
.list();
    
// Вывести список идентификаторов и имён пользователей в виде списка Map<String,Object>, отсортированного по возрасту в порядке убывания
query
    .from(user)
    .where(user.age.$gt(18))
    .param(
        new QueryParameter().orderBy(user.age.desc())
    )
.select(
    new Focus()
    .focus(user.id) // Псевдоним для типа краткого имени. Поле
    .focus(user.name, "user_name")
);
    
// Вычислить среднее значение возраста всех пользователей
query
    .from(user)
    .where(null)
.avg(user.age);

// Увеличить возраст всех пользователей на 1
query
    .from(user)
    .where(null)
.update(
    user.age.as(user.age.add(1))
);

// Удалить всех пользователей
query
    .from(user)
    .where(null)
.remove();

Приведённый выше запрос является стилем SQL, но иногда он не работает с реляционными базами данных или не нравится синтаксис, подобный SQL, поэтому здесь также предлагается стиль потока запросов.

// Список всех пользователей старше 18 лет
query
    .from(user).stream()
    .filter(user.age.$gt(18))
.list();
    
// Вывести список идентификаторов и имён пользователей в виде списка Map<String,Object>, отсортированного по возрасту в порядке убывания
query
    .from(user).stream()
    .filter(user.age.$gt(18))
    .sorted(user.age.desc())
    .map(
        new Focus()
            .focus(user.id)
            .focus(user.name, "user_name")
    )
.list();

// Вычислить средний возраст всех пользователей
query
    .from(user).stream()
    .mapToInt(user.age)
.average();

Все эти запросы имеют проверку типов.

Существующие реализации DataAccess

На данный момент разработана реализация, ориентированная на стандарт JPA, а также абстрактная реализация для ресурсов.

Реализация для JPA тестируется в среде тестирования с использованием Hibernate-EntityManager-4.0 и проходит тесты в HSQLDB и MySQL. Если вы загрузили исходный код, вы можете запустить тестовые примеры напрямую, HSQLDB будет работать в памяти.

Зависит от:

  • daf4j-api:0.1.1-RELEASE
  • slf4j-api:1.7.12
  • hibernate-jpa-2.0-api:1.0.1.Final

Конечно, для вывода журнала требуется дополнительная система журналов, такая как slf4j-simple/log4j+slf4j-log4j и т. д., и JPA также требует добавления зависимостей. Вы можете добавить зависимости самостоятельно или использовать Maven.

<dependencies>
    <dependency>
        <groupId>net.cassite</groupId>
        <artifactId>daf4j-ds-jpa</artifactId>
        <version>0.1.1-RELEASE</version>
``` ###JPQLDataAccess/JPQLDataSource

JPA — это часть JavaEE, стандарт для сохранения данных. Поэтому он был реализован. JPA предоставляет два способа запросов: JPQL и Criteria, но способ Criteria имеет большие ограничения, поэтому используется способ JPQL.

В реляционных базах данных можно выполнять join, group by, having, однако в daf4j-api этих элементов нет. Это связано с моими предыдущими размышлениями об упрощении SQL [1].

1. В SQL, если появляется агрегатная функция, то поля, которые появляются в этой функции, должны быть указаны в предложении group by.
2. Если агрегатная функция является частью условия, она должна быть помещена в предложение having.

То есть в большинстве случаев group by и having могут быть выведены.

При использовании JPA отношения соединения уже определены в сущности. Даже при написании JPQL вы будете писать только так:

```sql
select u from User u join u.roles r ...

Это может быть полностью автоматически сгенерировано.

Однако здесь есть некоторые правила использования.

Например, у пользователя (User) и роли (Role) есть связь «один ко многим». Если вам нужно запросить пользователей на основе ролей, например, всех пользователей с ролью «admin», вы должны написать так:

User user=new User();
Role role=new Role();
user.getRoles().add(role);
    
query
    .from(user)
    .stream()
    .filter(role.name.$eq("admin"))
.list();

Другими словами, вам необходимо указать поле соединения.

Если это отношение «один к одному», вам нужно заполнить его через setter.

####ResourceDataAccess

В версии 0.1.1 API предоставляет новую реализацию DataAccess. Она абстрагирует все «ресурсы».

Используйте объект Resource для представления ресурса, а интерфейс Source — для представления источника.

API поставляется с реализацией локального файла LocalFileSource. Используйте его следующим образом:

Query query=new Query(new ResourceDataAccess(new LocalFileSource));
Resource r = new Resource();
query
    .from(r)
    .where(r.location.$like("/Volumes/PROJECTS/openSource/DAF4J"))
.list();

Предложение where поддерживает $eq, $ne, $lt, $gt, $le, $ge, like. Среди них обязательно должно быть $eq или like для location. (like означает поиск из подресурсов.)

Предложение select поддерживает только count.

Предложение update поддерживает set для location и buffer. Для buffer требуется InputStream. Для location требуется строка или concat.

Когда транзакция включена, InputStream будет закрыт при фиксации или откате.

##Scala специальное использование Здесь не буду вдаваться в подробности, код говорит сам за себя:

import entity._

query from entity where age > 18 & id <> 1 param (orderBy(name.desc) top 1) list()

query from entity where age > 18 & id <> 1 param (orderBy(name.desc) top 1) select id ~(name, "a")

query from entity stream() filter age > 18 & id <> 1 sorted name.desc limit 5 list()

query from entity stream() filter age > 18 & id <> 1 sorted name.desc limit 5 map id ~(name, "a") list()

##DataSource DataSource используется для разделения логики в DataAccess, чтобы уменьшить вероятность ошибок кодирования и облегчить модульное тестирование.

Модуль DataSource состоит из следующих основных классов/интерфейсов:

  • DataSource — вход модуля, определяющий другие реализации;
  • ConditionParser — интерпретатор условий;
  • ExpressionParser — интерпретатор выражений;
  • AndOrParser — интерпретаторы «и» и «или»;
  • AroundParser — глобальный интерпретатор;
  • QueryParameterParser — интерпретатор параметров запроса;
  • EntityDataParser — интерпретатор полей сущностей (включая подзапросы);
  • UpdateEntryParser — интерпретатор целевых обновлений.

Подробности см. в документации и реализации JPQLDataSource.

Комментарии ( 0 )

Вы можете оставить комментарий после Вход в систему

Введение

Фасад доступа к данным для Java, более простая структура персистентного слоя, предоставляет унифицированный интерфейс для доступа к данным, а также более простой и понятный DSL. Развернуть Свернуть
MIT
Отмена

Обновления

Пока нет обновлений

Участники

все

Недавние действия

Загрузить больше
Больше нет результатов для загрузки
1
https://api.gitlife.ru/oschina-mirror/wkgcass-DAF4J.git
git@api.gitlife.ru:oschina-mirror/wkgcass-DAF4J.git
oschina-mirror
wkgcass-DAF4J
wkgcass-DAF4J
master