description : only one may be defined as writable all others must be specified read-only

Many To One 매핑에서 자주 발생하는 문제이다..
또한 추가적으로 One쪽 PK가 Many쪽에서도 PK로 사용된다면 JPA 초기 설정된 상태로는 100% 에러난다.

A와 B의 관계가 N:1이면 A와 B의 PK들은 아래의 구조를 가지게 된다.


	//MasterCodes.java (A와 B의 관계에선 A, 즉 Many 쪽 table)
	@EmbeddedId
	private MasterCodesPK id; //복합키

	@Column(name="CODE_NAME")
	private String codeName;

	//생략~~

	//bi-directional many-to-one association to MasterCodeGroups
	@ManyToOne(cascade = REFRESH)
	@JoinColumn(name="CODE_GROUP_SEQ")
	private MasterCodeGroups masterCodeGroup;
	
	// getter / setter 생략~
	//MasterCodeGroups.java (A와 B의 관계에선 B, 즉 One에 해당)
	@Id
	@Column(name="CODE_GROUP_SEQ")
	@GeneratedValue(generator = "MASTER_CODE_GROUPS")
	private int codeGroupSeq;

	@Column(name="CODE_GROUP_NAME")
	private String codeGroupName;

	// 생략~~

	//bi-directional many-to-one association to MasterCodes
	@OneToMany(mappedBy="masterCodeGroup", cascade = REFRESH)
	private Set masterCodes;

	// getter - setter 생략~


위 내용이 JPA로 Table에서 불러와 세팅 된 것인데 이대로 했다가 에러가 빵 뜨더라..;;
그 에러가 제목과 같은 에러인데 -
복합키로 구성될 경우 자신의 PK가 아닌 다른 Table의 PK를 변경할 수 있다면? 있을수 없는 일이다;;
즉 A와 B에서 A의 키는 A_PK, B_PK를 사용하는데 A테이블에서 B_PK를 변경할 수 있다면? 무결성이 깨지게 된다.;;
이때는 차라리 B에서 B_PK가 변경된다면 A에서도 B_PK가 변경되게 제약 조건을 설정하는게 좋다 -

그래서 read-only로 하라는 에러가 나오는 것인데 -

아래와 같이 A테이블에 설정을 더 적어 주어야 한다..


	//MasterCodes.java (A와 B의 관계에선 A, 즉 Many 쪽 table)
	@EmbeddedId
	private MasterCodesPK id; //복합키

	@Column(name="CODE_NAME")
	private String codeName;

	//생략~~

	//bi-directional many-to-one association to MasterCodeGroups
	@ManyToOne(cascade = REFRESH)
	@JoinColumn(name="CODE_GROUP_SEQ", nullable=false, insertable=false, updatable=false)
	private MasterCodeGroups masterCodeGroup;
	
	// getter / setter 생략~



아까와 동일하나 JoinColumn Annotation에 기타 속성이 잔뜩 들어갔다;; 저렇게하면 read-only가 된다.

시간이 없어서 문서를 다 읽어보지 않고 중요 부분만 읽은 후에 썼는데 -
시간 있으신 분은 아래 사이트에서 다 읽어보면 좋을 것 같다.

http://trycatchfinally.blogspot.com/2006/01/mapping-relationships-in-ejb-30.html
server 측 cmd 창에서 아래 실행.
mysql -u root -p
connect mysql
grant all privileges on mysql.* to cpn identified by 'cpn';
#--- 아래의 권한 설정 중 필요한 권한만 Y로 설정하여 부여 한다.
update user
set select_priv = 'Y',
insert_priv = 'Y',
update_priv = 'Y',
delete_priv = 'Y',
create_priv = 'Y',
drop_priv = 'Y',
reload_priv = 'Y',
shutdown_priv = 'Y',
process_priv = 'Y',
file_priv = 'Y',
grant_priv = 'Y',
references_priv = 'Y',
index_priv = 'Y',
alter_priv = 'Y',
show_db_priv = 'Y',
super_priv = 'Y',
create_tmp_table_priv = 'Y',
lock_tables_priv = 'Y',
execute_priv = 'Y',
repl_slave_priv = 'Y',
repl_client_priv = 'Y',
create_view_priv = 'Y',
show_view_priv = 'Y',
create_routine_priv = 'N',
alter_routine_priv = 'N',
create_user_priv = 'N'
where user = 'cpn';
commit;
flush privileges;
만약 권한이나 접속 IP 설정을 했다면 아래 문장을 실행하여야 한다.

{mysql_path}에서 mysqladmin -u root -p reload

이후 원격지에서는 설정한 권한으로 작업을 할 수 있다.

'DB > MySQL' 카테고리의 다른 글

Sample Database 다운로드  (0) 2012.11.06
InnoDB: No valid checkpoint found  (0) 2011.12.08
Fatal error: Can't open and lock privilege tables:  (0) 2011.12.08
접속 IP별 권한 설정.  (0) 2010.06.08
단순 다음에 기억이 안날까봐 여기에 적어 놓음.. ;;

형식 - UPDATE {TABLE} SET {COLUMN} FROM {SUB_QUERY} WHERE {CONDITION}

아래는 사용한 예..

UPDATE CUSTOMER_AUTO
SET   CUSTOMER_AUTO.WARRANTY_EXPIRED_DATE = dateadd(day, -1, dateadd(month, RTL.PERIOD_1, CUSTOMER_AUTO.REGIST_DATE))
    , CUSTOMER_AUTO.SERVICE_EXPIRED_DATE = dateadd(day, -1, dateadd(month, RTL.PERIOD_2, CUSTOMER_AUTO.REGIST_DATE))
FROM (
    SELECT A.COMM_NO
        , CASE WHEN A.DELIVERY_PRICE_SEQ = 'CS0001' THEN C.WARRANTY_PERIOD_GENERAL
              WHEN A.DELIVERY_PRICE_SEQ = 'CS0002' THEN C.WARRANTY_PERIOD_TAX_FREE
              WHEN A.DELIVERY_PRICE_SEQ = 'CS0003' THEN C.WARRANTY_PERIOD_DIPLOMAT
              WHEN A.DELIVERY_PRICE_SEQ = 'CS0006' THEN C.WARRANTY_PERIOD_RENT
              WHEN A.DELIVERY_PRICE_SEQ = 'CS0005' OR A.DELIVERY_PRICE_SEQ = 'CS0004' THEN 36
              ELSE 0 END
        AS PERIOD_1
        , CASE WHEN A.DELIVERY_PRICE_SEQ = 'CS0001' THEN C.WITHOUT_COST_PERIOD_GENERAL
              WHEN A.DELIVERY_PRICE_SEQ = 'CS0002' THEN C.WITHOUT_COST_PERIOD_TAX_FREE
              WHEN A.DELIVERY_PRICE_SEQ = 'CS0003' THEN C.WITHOUT_COST_PERIOD_DIPLOMAT
              WHEN A.DELIVERY_PRICE_SEQ = 'CS0006' THEN C.WITHOUT_COST_PERIOD_RENT
              WHEN A.DELIVERY_PRICE_SEQ = 'CS0005' OR A.DELIVERY_PRICE_SEQ = 'CS0004' THEN 36
              ELSE 0 END
        AS PERIOD_2
    FROM SALE_CONFER A
    INNER JOIN CUSTOMER_AUTO D ON A.COMM_NO = D.COMM_NO AND D.REGIST_DATE IS NOT NULL AND (D.WARRANTY_EXPIRED_DATE IS NULL OR D.SERVICE_EXPIRED_DATE IS NULL)
    INNER JOIN STOCK B ON A.COMM_NO = B.COMM_NO
    INNER JOIN AUTO_YEARS C ON A.AUTO_MODEL = C.AUTO_MODEL AND B.YEAR_SEQ = C.YEAR_SEQ
    WHERE A.DELIVERY_PRICE_SEQ IS NOT NULL AND A.COMM_NO IS NOT NULL AND A.SALE_FIXED_DATE >= {ts '2010-05-17 00:00:00'}
) RTL
WHERE CUSTOMER_AUTO.COMM_NO = RTL.COMM_NO AND REGIST_DATE IS NOT NULL AND (WARRANTY_EXPIRED_DATE IS NULL OR SERVICE_EXPIRED_DATE IS NULL) AND CUSTOMER_AUTO.COMM_NO IS NOT NULL


'DB > MSSQL' 카테고리의 다른 글

SELECT 후 UPDATE  (0) 2010.06.08
MS-SQL JDBC Library  (0) 2009.12.09

+ Recent posts