※量が増えてスクロールが面倒になったので記事を分割した。
→操作編
文法
なんかパスカルケースっぽい。
VBに近い文法に見える。
Genexus上で書いたコードの実態は、*.cfsファイルに保存されているようだ。
演算子
残念ながら++とか%はない
!はあるけど別の意味(リテラル)なので注意
&i = 0
&i = &i + 1
// 余りはMod
If Mod(&i, 3) = 0
...
EndIf
// ~以外は<>
If &a <> 0
...
EndIf
// 比較演算子は==ではなく=
If Not &a = 1
...
EndIf
リテラル
!を付けないと、内部的に文字列がため込まれていくらしい...。
再利用か何か狙ってるのだろうか?詳細は不明。
hoge.str = 'hage'
hoge.str = !'page'
If
ElseIfはないらしい
If &a <> 0
...
EndIf
Case
Do Case
Case &a = !'a'
...
Case &a = !'b'
...
OtherWise
...
EndCase
イベント構文
ユーザー定義イベントに数字を併記すると、対応するファンクションキー押下時に処理を割り当てることができる。
ただし、ブラウザ標準の機能が死ぬため注意。F12の開発者ツールとか。
// 起動時
Event Start
EndEvent
// 更新時(ユーザー定義イベント後も動いちゃう)
Event Refresh
EndEvent
// ユーザー定義イベント(F4割り当て)
Event 'sel' 4
EndEvent
機能的なところ
コード埋め込み?
地味に、他言語のコードを直接埋め込めるっぽい。
おそらくは、最初にプロジェクト設定で選択した言語限定だろうけど。
java for (int i = 0; i < 5; i++) {
java ...
java }
シングルクォートで囲っているのは、ユーザー定義イベント。
配置したボタンの名称を変更するには
1:プロパティから「On click Event」で「New」を選ぶ。
2:captionプロパティを編集する。
Enum的なもの
ドメインを使う。
ナレッジベースナビゲータからドメインを開いたら一覧が見れる。
プロパティのEnum Valuesから専用エディタを開ける。
キャスト
変換できないものがあったら0を返すらしい。
val(&str)
str(&num)
SDT
Newしてあげないと、メモリ割り当てされない。
For Eachとかで回してListにpushする時は
ループ毎にNewしないと、参照渡しになる故。
&HOGE_SDT = New()
一度定義したIDを変更する場合は、プロパティ上から編集する。
Structureタブで直接編集すると、元々のIDとは別項目として、新規項目扱いされるらしい。
「Is Collection」にチェックを入れると、リストとして扱ってくれる。
例外
基本は例外という考え方はなく
システムエラー以外は空文字とか0とかにキャストしてくるらしい。
Procedure呼び出し
Callで外から呼び出せる。
パラメータはRules枠で定義できる。
Rulesのパラメータ定義
parm(in: &hoge, out: &hage);
呼び出し方A
hogehogeProc.Call(&hoge, &hage)
呼び出し方B
&hage = hogehogeProc.Udp(&hoge)
最後のout項目限定で、Udp()って呼び出し方すると戻り値として返してくれる。
複数out項目を定義しても、Udp()で返ってくるのは最後の一個だけ。
つまり、他プロシージャの呼び出しの引数に渡せる。
hageProc.Call(hogehogeProc.Udp(&hoge))
プロシージャに複数メソッド定義
Rulesでのパラメタ定義が使えなくなるけど、こんな風に定義できる。
Stub sel(in:&cd, out:&rtn)
...
EndStub
Stub del(in:&cd, out:&rtn)
...
EndStub
呼び出し側
hoge.sel(&cd, &rtn)
hoge.del(&cd, &rtn)
サブルーチン
privateメソッドを定義。
外部からは呼べない。
戻り値を返せないので、サブルーチン内部ではグローバル変数を書き換える。
Sub 'calc'
Do 'multiple'
EndSub
セッション
SDTとかのデータの受け渡しはセッションを使える。
先にVariablesタブでWebSessionの変数を定義しとかないと補完が聞かないのでつらい。
// シリアライズ
&webSession.Set('key', &sdts.ToXml())
// デシリアライズ
&sdts.FromXml($webSession.Get('key'))
DB周り
検索条件を絞る
when句を使うと、条件を満たす場合のみ、where句を付与できるようになる。
Likeと検索文字列を'%'と結合させて、前方一致やら部分一致やらを実現できる。
For Each m_shohin Order ms_shohin_cd
where ms_shohin_cd = &ms_shohin_cd when not &ms_shohin_cd.IsEmpty()
where ms_shohin_nm like '%' + &ms_shohin_nm + '%' when not &ms_shohin_nm.IsEmpty()
where ms_shohin_price > &ms_shohin_price when &ms_shohin_price > 0
EndFor
キーさえ一意なら、テーブル名の指定もいらなかったりする。
For Each
where ms_shohin_cd = &ms_shohin_cd when not &ms_shohin_cd.IsEmpty()
EndFor
外部キーの場合は、逆にテーブル名を指定してあげないと、エラーになる。
// m_shohin_hd, m_shohin_dtlだけを結合したいが、
// テーブル名を省くとms_shohinもくっつけようとしてリレーションNGになる
For Each m_shohin_hd, m_shohin_dtl
where ms_shohin_cd = &ms_shohin_cd when not &ms_shohin_cd.IsEmpty()
where m_shohin_hd_del_flg = False
where m_shohin_dtl_del_flg = False
EndFor
集約はたぶんこう(未検証)
For each
where ms_shohin_del_flg = False
&TotalAmt = Sum(ms_shohin_category, ms_shohin_sel_div = !'1')
EndFor
Insert/Update/Delete
// INSERTだけならこれで
New
ms_shohin_cd = &ms_shohin_cd
ms_shohin_nm = &ms_shohin_nm
ms_shohin_price = &ms_shohin_price
Endnew
For Each m_shohin
where ms_shohin_cd = &ms_shohin_cd
ms_shohin_nm = &ms_shohin_nm
ms_shohin_price = &ms_shohin_price
when none
New
ms_shohin_cd = &ms_shohin_cd
ms_shohin_nm = &ms_shohin_nm
ms_shohin_price = &ms_shohin_price
Endnew
EndFor
For Each m_shohin
where ms_shohin_cd = &ms_shohin_cd
Delete
&rtn = 1
when none
&rtn = 2
EndFor
トラブルシューティング
・was wrong...とか言われる
→似たようで互換性がない型が、おそらくAutodefined Variablesで登録されている
・Numeric = Varcharとか言われる
→型が間違っている、Autodefined Variablesのせいなのか、変数定義してないからかは要確認。意図的にやってるならキャストする。
・日付はどうやって初期化するの
→.SetEmpty()を使う
・DBの再編成がこける
→型変更とかのケースでやってしまいがち。DDLはgeneXusが勝手に発行するので、手動でDDLを発行せず、再編成プログラムに任せること。
・実行時にCaused by: com.genexus.GXRuntimeException: org.postgresql.util.PSQLException: ERROR: portal "C_65" does not exist
→整数項目にマイナスつっこもうとしてたり、色々…
・java.lang.reflect.InvocationTargetExceptionが起きる
自分で書いたコードじゃないんだからリフレクションエラー言われてもわけわからねーよぉ!!
ナレッジベースのフォルダ階層の中に出力されたjavaファイル見て、javaベースでロジック追いかけるのが一番早い気がする。
C:\GenKB\JavaModel\web\ws***.java
・portal "C_[0-9]+" does not exist
HTTPステータス 500 - java.lang.reflect.InvocationTargetException
Caused by: com.genexus.GXRuntimeException: org.postgresql.util.PSQLException: ERROR: portal "C_136" does not exist
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2101)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1834)
at org.postgresql.core.v3.QueryExecutorImpl.fetch(QueryExecutorImpl.java:2036)
at org.postgresql.jdbc2.AbstractJdbc2ResultSet.next(AbstractJdbc2ResultSet.java:1821)
at com.genexus.db.driver.GXResultSet.next(Unknown Source)
at com.genexus.db.ForEachCursor.next(Unknown Source)
at com.genexus.db.DataStoreProvider.readNext(Unknown Source)
NG
For &Upd_SDT in &Upd_SDTs
For Each
where CrtDate = &ServerNow
OracleAcntgDataKbn = !'9'
Commit
EndFor
EndFor
OK
For &Upd_SDT in &Upd_SDTs
For Each
where CrtDate = &ServerNow
OracleAcntgDataKbn = !'9'
EndFor
Commit
EndFor
For &Upd_SDT in &Upd_SDTs
For Each
where CrtDate = &ServerNow
OracleAcntgDataKbn = !'9'
EndFor
EndFor
Commit
ほか
続きは随時追記していく方式で。