이 블로그 검색

2011년 9월 28일 수요일

오라클 인덱스2

※ 인덱스생성 명령을 실행하면 해당 테이블에 테이블락이 자동으로 걸린다.
그래서 서비스상태에서는 인덱스를 주면 장애가 날수 있습니다.

Index 정의

1) 조회속도를 향상시키기 위한 데이터베이스 검색 기술

2) 색인이라는 뜻으로 해당 테이블의 조회결과를 빠르게 하기 위해 사용합니다.
보통 INDEX를 테이블의 특정 컬럼에 한개이상을 주게 되면 Index table 이 따로 만들지는데
이 INDEX table 에는 인덱스컬럼의 로우의 값과 rowid 값이 저장되게 되며 로우의값은 정렬된 B-TREE 구조로 저장시켜두어 검색시 좀더 빠르게 해당 데이타를 찾는데 도움을 준다.
하지만 UPDATE,INSERT,DELETE 시에 속도가 느려진다는 단점이 있다.
왜냐하면 INSERT, UPDATE, DELETE 시에는 원본TABLE은 물론 INDEX table 에도 데이타를 갱신시켜 주어야 하기 때문입니다.
하지만 너무 작은 로우(레코드)가 있는 TABLE에 INDEX를 사용하게 되면 index의 효력을 제대로 발휘못하며 반드시 INDEX키를 조건으로 검색시에는 연산이나 가공을 하면 INDEX를 탈수없다.

※ 테이블을 생성하고 컬럼을 만든후 데이타를 삽입하면 하나의 로우가 생성되며 이 로우는 절대적인 주소를 가지게 됩니다. 이 절대적인 주소를 ROWID 라고 합니다.

INDEX가 필요한 이유?

조회 속도를 최대한 줄일수 있다.

참고
인덱스를 만들 때 현재 컬럼수가 너무 많으면 DML의 성능이 떨어지고 너무 부족하면
쿼리의 성능이 떨어집니다. 데이터가 많고 B*Tree Index인 경우 컬럼level이 하나
늘어날 때 그에 따른 node의 추가가 엄청나게 일어날 수 있습니다
이런 node들이 너무 많으면 쿼리성능도 좋을 수 없습니다.
인덱스는 일반적으로 최대 5개 컬럼 내외정도로 상황에 따라 합리적으로 구성합니다.

INDEX가 필요한 경우?

1) 데이터가 적은(수천건 이상) 경우이거나 조회속도가 너무 느리면 인덱스를 설정하는
것이 성능이 좋습니다.

2) 조회결과가 전체 데이타수의 3~5% 미만일 경우에 인덱스스캔이 효율적이고
적은비용으로 빠르게 데이터를 찾아낼수있습니다.
하지만 Acess 대상범위가 전체범위의 3~5%이상쯤 되면 인덱스스캔 보다 풀스캔이 휠씬
유리합니다.

인덱스 스캔 = Index Scan
풀 스캔 = Full Scan

INDEX가 불필요한 경우?

1) 데이터가 적은(수천건 미만) 경우에는 인덱스를 설정하지 않는게 오히려 성능이 좋습니다.
2) 조회 보다 삽입, 수정, 삭제 처리가 많은 테이블
3) 조회결과가 전체행의 15% 이상 읽어들일것으로 예상될때

Index 튜닝의 시기단계

하드웨어
DBMS 환경체크 - INDEX설정 및 파티셔닝체크 - SQL최적화  등의 레벨 순서로 튜닝합니다.

소프트웨어
쿼리문의 조회조건이 인덱스를 타는지 체크한다.(조금 중요)

쿼리문의 JOIN키가 모두 INDEX 설정이 되어 있는지 체크한다. INDEX설정이 되어 있지 않는 컬럼을 JOIN키로 지정했다면 조회속도가 많이 느려질수 있다.(많이 중요)

INDEX 생성하는 방법?

자동 생성

유일 인덱스는 테이블 정의시 PRIMARY KEY와 UNIQUE KEY 제약조건을 정의할때 자동으로 생성한다.

수동 생성

사용자는 행에 대한 액세스 시간을 향상 시키기 위해 열에서 유일하지 않은 인덱스를 생성할수 있다.

INDEX 생성 문법?

사용형식

CREATE INDEX index_name ON table_name (column_name)
--단일 인덱스 지정
CREATE INDEX index_name ON table_name (column_name1,column_name2,column_name3)
--다중 인덱스(복합 인덱스) 지정

※ 복합 인덱스로 지정해준 테이블에서 복합 인덱스를 타게 하려면 복합 인덱스로 준 컬럼
을 조회쿼리에서 모두 조회조건에 사용해야 인덱스를 탈 확률이 높아진다.

사용예제

create index index_a_date on account(a_date);
create index index_a_date on account(a_date, b_date, c_date);

※ null 허용 컬럼은 인덱스를 만들수 없습니다.

INDEX 가능 컬럼

인덱스는 모든 컬럼에 적용가능하다.
그런데 오라클은 가공시킨 컬럼에도 적용가능하다. 아래 참고

CREATE INDEX IDX_NAME ON TABLE_NAME(ROUND(PRICE1-PRICE2));

ROUND(PRICE1-PRICE2) 는 컬럼은 아니지만 컬럼을 가공해서 만든것이다.
이런 가공컬럼은 다음과 같은 SQL 쿼리로 인덱스를 탈수 있다.

SELECT * FROM TABLE_NAME WHERE ROUND(PRICE1-PRICE2) > 0

※ 인덱스 줄때의 가공컬럼과 같아야 합니다.

SQL 쿼리의 INDEX SCAN 유무 체크 방법

1. 상용 DB 관리도구를 이용하는 방법

PL/SQL Developer, Toad 같은 도구에서 SQL문을 작성하고 실행하면 Explain plan 에서 확인 가능합니다.

INDEX를 사용해야할 컬럼은?

where절이나 조인 조건에서 자주 사용되는 열에 생성
열은 광범위한 값을 포함할때
열은 많은수의 null값을 포함할때
조회결과가 전체행의 2-4% 보다 적게 읽어들일것으로 예상될때
--테이블이 클때 적은 양의 로우를 검색할때 인덱스를 줍니다. 적은 양을 검색하는데 테이블을 전체 풀스캔하면 시간이 오래 걸려서 꼭 index를 줘야 합니다.

INDEX를 사용하지 말아야할 컬럼은?

테이블에 데이타가  작은 경우
where절에 자주 사용되지 않는 열은 사용되지 않는다.
조회결과가 전체행의 2-4% 이상을 읽어들일것으로 예상될때
테이블이 자주 갱신된다.

INDEX 생성시 고려사항?

고려사항

인덱스가 적용된 컬럼이 조건식에서 인덱스를 탈수있게  하려면 해당컬럼을 가공하지않거나 연산을 하지 않은 상태에서 비교해야 인덱스를 탑니다.
예를들어 연락처컬럼의경우(016-293-1965) 016 만 따로 문자열을 잘라(가공) 조건검색하면 인덱스를 타지 않습니다.
왜냐하면 인덱스 컬럼에 변형이 일어나면 상대값과 비교되기 전에 먼저 가공이 된 후에 비교된다.하지만 인덱스는 가공되기 전의 값으로 생성되어 있기 때문에 당연히 인덱스를 사용할 수 없게 된다. 여기에서 외부적(External) 변형이란 사용자가 인덱스를 가진 컬럼을 어떤 SQL함수나 사용자 지정함수(User Defined Stored Function), 연산, 결합(||) 등으로 가공을 시킨 후에 발생되는 것이며 이러한 경우는 인덱스를 탈수 없어 변형이 일어나지 않도록 제대로 기술해야 합니다.
그렇기때문에 016과 293과 1965를 각각의 컬럼으로 만들어 저장한후 각각의 컬럼에 인덱스를 주면
아무런  가공없이 조건 검색이 가능하므로 인덱스를 탈수 있습니다.

테이블 컬럼에 인덱스가 있따면 테이블 컬럼을 변경하는것보다 비교값을 변경하여
비교해주는데 좋다. 왜냐면 그래야 인덱스를 타기 때문이다.
WHERE to_char(joindate, 'yyyymmdd') = '20070612'
WHERE joindate = TO_DATE('20070612','yyyymmdd')

아래는 인덱스를 타지 않습니다.

SELECT * FROM ACCOUNT WHERE A_DAY+1>2;
SELECT * FROM ACCOUNT WHERE SUBSTR(A_STRDAY,1,1)='월';
SELECT * FROM EMP WHERE  EMP_ID = NVL(EMP_ID,'10');

아래는 인덱스를 탑니다.

SELECT * FROM ACCOUNT WHERE A_STRDAY='월요일';
SELECT * FROM ACCOUNT WHERE A_DAY>2;
SELECT * FROM    EMP WHERE  EMP_ID = NVL('10','20');
SELECT * FROM ACCOUNT WHERE A_STRDAY like '월요일%';

※ 첫번째 쿼리부터 인덱스효과가 크게 나타나는 순입니다.

INDEX 타는 경우와 안타는 경우

안타는 경우
1. SELECT * FROM emp WHERE empno <> '7369';

※ 오라클에서는 인덱스 타게 가능(exists 이용)
SELECT * FROM emp WHERE not exists
(select empno FROM emp WHERE empno = '7369' and a.empno = b.empno);

INDEX 보기?

SELECT * FROM USER_INDEXES
--데이터 사전 뷰는 인덱스의 이름과 그것의 유일성을 디스플레이 합니다.

SELECT * FROM USER_IND_COLUMNS
--뷰는 인덱스명,테이블명,열명을 디스플레이 합니다.

SELECT * FROM ALL_OBJECTS where object_type='INDEX';
--현재 계정에 생성된 모든 인덱스 보기(속도느림)

SELECT * FROM USER_OBJECTS WHERE OBJECT_TYPE='INDEX';
--현재 계정에 생성된 모든 인덱스 보기(속도빠름)

select ic.index_name,
       ic.column_name,
       ix.uniqueness
from   user_indexes ix, user_ind_columns ic
where  ic.index_name = ix.index_name
and    ic.table_name = 'ACCOUNT';
--ACCOUNT TABLE의 인덱스 정보를 검색합니다.

INDEX 삭제?
사용형식
DROP INDEX INDEX_NAME;
사용예제
DROP INDEX BYC_LOVE_IDX;

※ TABLE이 삭제되면 INDEX도 삭제된다.
※ 인덱스의 소유자와 DROP ANY INDEX권한을 가진 사람만 인덱스 삭제가 가능합니다.

datecolumn => '20060517' and datecolumn <= '20060517' 좌측의 쿼리가 인덱스 안
타는 경우
1. 인덱스키가 아님
2. 복합키 인덱스인데 첫번째 컬럼에 조건을 안준 경우
3. 인덱스 스캔을 했을때 전체 데이터의 10~15% 이상이 되어 옵티마이져가 판단했을때
4. 인덱스 스캔이 불리하다고 판단되어 강제로 인덱스안타는 풀스캔 타는 경우
5. 좌변이 가공되어 인덱스 안탐

자주 쓰이지 않는 통계용 쿼리에는 인덱스를 주지 않는다.
여기서 인덱스를 준다는 얘기는 조건절에 인덱스를 안타는 컬럼에 인덱스를 생성해준다는
얘기이다. 이때는 create temp table as 해서 임시 테이블 만들어 통계 내용을 모두 담은후에
해당 조건컬럼에 인덱스를 만들어 쿼리하는게 좋다.

오라클 인덱스1


테이블의 데이터들은 데이터파일내에 위치하게 되고, 이를 검색하기 위해서는 많은 수의 레코드들을 비교해야 합니다.
그래서 특정 필드들을 이용해서 B+트리를 구성해 놓는 것을 인덱스하고 보시면 되겠습니다.
자료구조에서 트리의 경우는 검색이 빠르다는 장점을 가지고 있죠.
결국 테이블의 데이터를 가지고 인덱스를 만들어서 검색속도를 향상시키는 것입니다.
대부분의 DB에서 기본적으로 primary key는 인덱스를 자동으로 생성하는 경우가 많습니다.
물론 이 인덱스의 종류는 다양합니다. 데이터의 종류나 성향에 따라서 검색속도를 향상시키는 몇가지의 방법이 존재하는 것이죠.
이 인덱스는 검색 쿼리문의 조건절에 명시된 조건절을 따르게 됩니다.
조건이 많은 경우는 디비내의 옵티마이져가 선택한 인덱스를 이용해서 검색을 하게 됩니다.(이는 디비마다의 알고리즘이 다릅니다.)
그래서 오라클의 경우는 옵티마이져가 정한 인덱스가 아닌, 개발자/DBA가 정한 인덱스를 타도록 지정하는 힌트라는 옵션도 있습니다.
결론적으로 인덱스는
1. 검색속도 향상을 위한 것이다.
2. 내부적으로 B+ 트리를 이용한다.
3. 데이터의 성향에 따라서 다양한 인덱스가 존재한다.
4. INSERT/UPDATE/DELETE시는 인덱스가 성능을 약화시킨다.
5. 인덱스가 다수 존재하는 경우 조건절에 따라서 타는 인덱스가 달라진다.
이정도의 특성이 있겠습니다.

-----------------------------------------------------------------------------


결합인덱스의 생성지침

- 단 하나의 테이블에서 컬럼들을 참조해야 한다
- 최대 16개 컬럼을 생성할 수 있다
- 결합 인덱스의 전체 컬럼 길이는 db_block_size 파라미터의 값을 1/2을 초과하면 안된다.
- 결합 인덱스를 생성할 때는 선택도가 좋은 컬럼을 선행컬럼으로 결정해야한다(즉 앞에 둔다)
- 선행 컬럼을 결정하기 힘든 경우에는 자주 사용되는 컬럼을 선행 컬럼으로 결정한다.
- 결합인덱스의 수가 많으면 많을수록 데이터의 검색속도는 향상될 수 있으나 오히려
  DML문의 수행성능은 저하될 수 있다

index의 분석
-최초로 인덱스를 생성한 이후 테이블에 DML문이 자주 발생하게 되면 밸런스 구조는 깨지고
 좌,우의 구조도 달라지게 된다

 이러한 현상이 발생하면 좋은 성능을 보장해 줄 수 없기 때문에 데이터 베이스 관리자는
 주기적으로 또는 비 주기적으로 밸런싱이 깨진 인덱스를 분석하고 인덱스를 재구성하는 작업을
 해야만 성능을 기대할 수 있다. 인덱스의 각 블록에 저장되어 있는 인덱스 키의 개수가 블록
 마다 틀리게 되면 밸런싱이 깨지게 된다.

-----------------------------------------------------------------------------------------------------------------


*인덱스의 밸런싱 구조상태를 확인하는 방법
SQL> analyze index i_big_emp_cp_empno validate structure;
인덱스가 분석되었습니다.

SQL> select (del_lf_rows_len/ lf_rows_len) * 100 as "Balancing"
          from index_stats;
 Balancing
----------
         0   <--완벽한 밸런싱을 유지함


-------------------------------------------------------------
-밸런싱을 깨기위해 행 삭제

SQL> delete big_emp_cp
        where empno > 1 and empno < 3000;
2879 행이 삭제되었습니다.

SQL> analyze index i_big_emp_cp_empno validate structure;
인덱스가 분석되었습니다.

SQL> select (del_lf_rows_len/ lf_rows_len) * 100 as "Balancing"
         from index_stats;
 Balancing
----------
9.49721286 <--인덱스의 밸런스 정도가 9.49%정도 깨짐

*인덱스의 재구성

-일반적으로 인덱스 밸런싱이 20%정도를 초과하면 성능이 저하될 수 있다고 본다
 좋은 성능을 기대하기 위해서는 반드시 인덱스를 재구성해야 한다.

SQL> alter index i_big_emp_cp_empno rebuild nologging;
인덱스가 변경되었습니다.

SQL> analyze index i_big_emp_cp_empno validate structure;
인덱스가 분석되었습니다.

SQL>  select (del_lf_rows_len/ lf_rows_len) * 100 as "Balancing"
  2   from index_stats;

 Balancing
----------
         0
SQL>

2011년 9월 21일 수요일

enhancer error


SajuDataTable does not seem to have been enhanced.

You may want to rerun the enhancer and check for errors in the output." has no table in the database, but the operation requires it. Please check the specification of the MetaData for this class.

2011년 9월 19일 월요일

editor ValueListBox

solar_yearEditor = new ValueListBox<String>(new Renderer<String>(){}

solar_yearEditor.setAcceptableValues(yearList);

=>solar_yearEditor 생성후 곧바로 setAcceptableValues 메소드로 설정을 하면
    null값이 하나더 추가된다.


이걸 없애기 위해서는 solar_yearEditor.setValue("값");로 설정을 하던가,
아니면 setAcceptableValues호출전 solar_yearEditor.setValue("값");로 하나의 값을 추가 후
setAcceptableValues을 호출하면 null은 추가되지 않는다.

editor listbox

http://stackoverflow.com/questions/5683977/how-to-edit-a-multi-value-field-with-gwt-editor-framework



예시2

public class MyListBox extends ListBox implements
LeafValueEditor<String> {

@Override
public void setValue(String value) {
if (value == null) {
 setSelectedIndex(-1);
 return;
}

for (int i=0;i<getItemCount();i++) {
if (getValue(i).equals(value)) {
setSelectedIndex(i);
return;
}
}

for (int i=0;i<getItemCount();i++) {
if (getItemText(i).equals(value)) {
setSelectedIndex(i);
return;
}
}

}

@Override
public String getValue() {
if (getSelectedIndex() == -1)
return null;

if (getItemText(getSelectedIndex()).trim().equals(""))
return null;

String value = getValue(getSelectedIndex());

if (value != null) {
return value;
}

return getItemText(getSelectedIndex());
}

}

2011년 9월 17일 토요일

appengine jdo + gwt(requestFactory) 오류

  • 오류메시지

Primary key for type Account is of unexpected type java.lang.String
(must be String, Long, or com.google.appengine.api.datastore.Key) 






  • 해결책



Try to add this line to your id:
        @Extension(vendorName="datanucleus", key="gae.encoded-pk",
value="true") 

java annotation3

 annotation의 적용 사례로
프로젝트의 유스케이스를 추적하는 어노테이션을 작성하는 것을 정리해 보도록 하겠습니다.

 프로젝트 관리자는 구현된 유스케이스의 수를 이용하여 프로젝트의 진척도를 알 수 있으며 개발자는 시스템 내의
비즈니스 규칙을 변경하거나 디버깅할 때 유스케이스를 쉽게 찾을 수 있으므로 프로젝트의 유지보수를 쉽게 할 수 있을것입니다.

- @UseCase 선언
UseCase.java

//: annotation.usecase/UseCase.java
package annotation.usecase;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase {
public int id();
public String description() default "no description";
}
- 다음은 클래스의 메소드에 유스케이스 정보를 기록한 예제입니다.
PasswordUtils.java
//: annotation.usecase/PasswordUtils.java
package annotation.usecase;

import java.util.List;

public class PasswordUtils {

@UseCase(id = 47, description = "password must contain at least one numeric")
public boolean validatePassword(String password){
return (password.matches("\\w*\\d\\w*"));
}

@UseCase(id = 48)
public String encryptPassword(String password){
return new StringBuilder(password).reverse().toString();
}

@UseCase(id = 49, description = "New password can't equal previously used ones")
public boolean checkForNewPassword(List<String> prevPasswords, String password){
return !prevPasswords.contains(password);
}
}

*어노테이션 프로세스 작성하기!
어노테이션을 읽고 처리할 수 있는 프로세서가 없다면 어노테이션은 단지 주석에 불과할 뿐입니다.
그러므로 어노테이션을 사용하는 과정에서 해당 프로세서를 정의하고 적용하는 것이 중요합니다.
자바 SE5는 이러한 툴을 만들기 위한 리플렉션 API의 확정성을 제공합니다.

- 다음은 어노테이션을 적용한 PasswordUtils 클래스를 읽고 리플렉션을 사용하여 @UseCase를 검색하는 어노테이션 프로세스 입니다.
UseCaseTracker.java

package annotation.usecase;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class UseCaseTracker {

public static void trackUseCases(List<Integer> useCases, Class<?> cl){
for(Method m : cl.getDeclaredMethods()){
UseCase uc = m.getAnnotation(UseCase.class);
if(uc != null){
System.out.println("Found Use Case :" + uc.id() + " " + uc.description());
useCases.remove(new Integer(uc.id()));
}
}
for(int i : useCases){
System.out.println("Warning : Missing use case-" + i);
}
}
/**
* @param args
*/
public static void main(String[] args) {
List<Integer> useCases = new ArrayList<Integer>();
Collections.addAll(useCases, 47, 48, 49, 50);
trackUseCases(useCases, PasswordUtils.class);
}

}

-실행결과







*어노테이션 요소

UseCase.java에 정의된 @UseCase 태그는 int 형의 id요소와 String 형의 description 요소를 가지고 있습니다.
다음은 어노테이션 요소에 허용되는 타입의 목록입니다.
- 모든 기본형 타입(int, float, boolean 등)
- String
- enum
- Annotation
- 상기 타입의 배열

->포장클래스 (Wrapper Class) 는 사용할수 없다.

자 이정도면 어느정도 annotation 에 대한 감이 잡히시는지요?
시간이 된다면 이어서 어노테이션을 이용하여 데이터베이스 생성 스크립트를 만들어주는 예제에 대해서
정리해 보도록 하겠습니다. 

java annotation2

* 어노테이션의 정의일반적인 인터페이스의 정의와 매우 유사함
컴파일러는 다른 자바 인터페이스와 마찬가지로 어노테이션을 클래스로 컴파일 한다.


package annotation.begin;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test { }
어노테이션 정의시 @Target, @Retention 이라는 메타-어노테이션이 필요함.
@Target 은 어노테이션을 적용할 대상(예를들면 메소드 또는 필드)
@Retention 은 해당 어노테이션이 소스코드(SOURCE), 클래스파일(CLASS), 또는 런타임(RUNTIME) 중 어디에서 적용되는지 정의.

위의 @Test와 같이 요소를 가지지 않은 어노테이션은 표식 어노테이션(marker annotation)이라고 불린다.

java annotation

컴파일러나 외부툴들에게 부연설명을 하는 역할을 한다.

예를들면,

@Override

JDO에서
@Version

등이있다.

기존에는 이런 정보들을 xml파일로 작성하여 해당 툴들에게 알렸다.

2011년 9월 9일 금요일

appengine test datastore page

http://127.0.0.1:8888/_ah/admin/datastore

jdo 쿼리오류. org.datanucleus.store.appengine.query.StreamingQueryResult cannot be cast

org.datanucleus.store.appengine.query.StreamingQueryResult cannot be cast ~~

List<SajuDataTable> sajuInfo = (List<SajuDataTable>)query.execute(UserServiceWrapper.get().getCurrentUserId());

이런씩으로 List로 받아야한다.
SajuDataTable로 곧바로 캐스트가 않됨.
왜냐하면 여러행이 나올수 있기때문...

2011년 9월 8일 목요일

gwt 이클립스로 프로젝트 import

build.xml파일에 아래내용이 있으면 ant eclipse.generate  실행후 import한다.


- <target name="eclipse.generate" depends="libs" description="Generate eclipse project">
- <java failonerror="true" fork="true" classname="com.google.gwt.user.tools.WebAppCreator">
- <classpath>
  <path refid="project.class.path" />
  </classpath>
  <arg value="-XonlyEclipse" />
  <arg value="-ignore" />
  <arg value="com.google.gwt.sample.dynatablerf.DynaTableRf" />
  </java>
  </target>

request factory jars파일

RUN환경 클래스패스에
 - validation-api-~~.jar
 - gwt-servlet-deps.jar

등을 추가해야함


2011년 9월 4일 일요일

RequestFactory


Entities : 서버

Entity Proxies : shared, 클라이언트에서 접근가능한 함수 선언

Value Proxies : shared

RequestFactory Interface : shared, Request클래스들을 정의


RequestContext : shared, 클라이언에서 호출할 Request stub 정의



클라이언트에서 사용방법
  - 직원 가져오기
requestFactory.employeeRequest().findEmployee(employeeId).fire(
    new Receiver<EmployeeProxy>() {
      @Override
      public void onSuccess(EmployeeProxy employee) {
      ...
      }
    });

 - 새로운 직원 생성
EmployeeRequest request = requestFactory.employeeRequest();
EmployeeProxy newEmployee = request.create(EmployeeProxy.class);
newEmployee.setDisplayName(...);
newEmployee.setDepartment(...);
...
Request<Void> createReq = request.persist().using(newEmployee);