プログラマ38の日記

主にプログラムメモです。

Salesforce: ナレッジを一括で公開する

Salesforceのナレッジをまとめて登録し、そのまま公開したい場合があります。

その際のやり方は次のようになります。

 

ナレッジをまとめて登録する

データローダをはじめとするAPIで登録が可能です。

f:id:crmprogrammer38:20170731182247p:plain

上記の、ナレッジの記事タイプの詳細で表示されているAPI参照名がオブジェクトAPI名となり、通常のオブジェクトの同じように登録を行います。上の画面では「type1__kav」がオブジェクトAPI名です。

そして登録後は「ドラフト記事」として保存されます。データローダ(API)で「type1__kav」をselectすると「ドラフト記事」は取得できないため、「type1__kav」にinsert後、「type1__kav」をselectすると結果に表示されません。、公開状況(PublishStatus)に"Draft"の検索条件を指定しないと結果が取得できません。他のオブジェクトの違いに多少戸惑います。

2017/8/17:__kavのオブジェクトからデータを取得する際には、公開状況(PublishStatus)に何も検索条件を指定しないと、公開状況(PublishStatus)が"Online"の条件がデフォルトとなることがわかりました。記載が間違えていたので訂正しました。

 

余談:ナレッジをまとめて削除する

「type1__kav」は、insert、upsert、updateが可能で、deleteはできません。deleteは「type1__ka」で行います。

 

ナレッジをまとめて公開する

f:id:crmprogrammer38:20170731183644p:plain

画面から行う場合は、「記事の管理」タブのドラフト記事から、複数のナレッジにチェックを入れて公開ボタンをクリックします。

それとは別にナレッジ用に用意されているApexClassからも公開できます。

List<KnowledgeArticle> rows = [Select  Id  From   KnowledgeArticle
where id not in ( select KnowledgeArticleId from KnowledgeArticleVersion) limit 100];
[Select KnowledgeArticleId From KnowledgeArticleVersion where PublishStatus = 'Draft' limit 100 ]

for( KnowledgeArticle row : rows ){
KbManagement.PublishingService.publishArticle(row.Id, true);
}

上記のコードで公開ができます。コードでKnowledgeArticle、KnowledgeArticleVersionを使いましたが、type1__ka、type1__kavとしても同じです。
※2017/8/17 公開状況(PublishStatus)に"Draft"の検索条件を入れれば、KnowledgeArticleVersionから取得できることがわかりSOQLを修正しました。

KnowledgeArticle、KnowledgeArticleVersionは全ての記事タイプを通してナレッジを管理できるオブジェクトです。

soqlでlimitを入れていますが、使ってみた結果100件が限界でした。ですので、100件以上まとめて公開する場合は、上記を全て公開できるまで繰り返すことになります。

 

Salesforce: SOQLの検索条件で、半角全角の区別ではまったこと

SOQLで検索条件は、半角全角の区別ではまりました。
何ではまったかというと、検索条件で指定したのは半角なのに、検索結果に全角も含まれていたからです。

 

はまった経緯は次です。

  • 半角の"x01"と全角の"x01"は分けてコード登録を行います。
  • Apex処理内でコードを使って別のデータとのひもづけを行う処理を作ろうとしました。

 

はまった結果は次です。

  • Apex内で半角の"x01"にひもづけてレコードを作成しようとして、半角の"x01"を検索条件としてSOQLを実行しました。ですが、その結果に、全角の"x01"も含まれていて、本来であればひもづけは不要な全角の"x01"にもレコードをひもづけてしまいました。

 

Salesforceでの半角全角・大文字小文字の区別

f:id:crmprogrammer38:20170728084239p:plain

ユニーク項目で、上記の「大文字と小文字を区別する」にすると、大文字小文字は区別されてますが、半角・全角の区別はありません。

※ただし、半角カナと全角カナは異なる文字として扱われます。

逆にいうとユニーク項目でない場合や、ユニーク項目でも上記の「大文字と小文字を区別しない」にチェックしていると、半角全角と大文字小文字が区別されません。

 

どう対処するか

  1. SOQLで検索結果に対して再度、指定した条件でフィルタする処理を作る。(Apexでの文字の比較は半角全角・大文字小文字は区別します)
  2. もしくはSalesforce以外で、要件を満たす半角全角・大文字小文字の区別ができるデータベースなどを用意してそちらの処理結果をSalesforceに登録する。

2での対策は、Salesforce以外にもサーバが必要とし、余計面倒ですので、1の検索結果にさらにフィルタする処理を作るのが現実的と思います。

 

Salesforceでキーとして扱う項目は、半角大文字で統一するなどルールを決めておくのが一番かなと思いました。

Salesforce: パーセント項目をApexで普通に掛け算すると100倍になる

Salesforceのパーセント項目の使い方を間違って値が100倍になってました。

間違った理由は、数値項目とパーセント項目を単純に掛け算したからで、正しい使い方は、数値項目とパーセント項目を掛け算した後、100で割る必要があります。

 

例えば、「24%」 というパーセンテージがあった場合、SOQLでパーセント項目を取得すると結果は 「24」です。

数式項目は、戻り値のデータ型で表示が変わったりするので、使い方のメモになります。

 

「24%」をサンプルの値とした場合の各パターン別の値

登録/参照パターン
データローダ(API)で登録する 24
データローダ(API)で取得する 24
画面で登録する 24
画面で参照する 24%
数式:戻り値のデータ型がパーセント 24%
数式:戻り値のデータ型が数値 0.24
Apexで登録する 24
Apexで取得する 24

 

こう書くと、Apexの中でSOQLで取得結果で掛け算する時は100で割らないといけないのはわかりますが、Excelで慣れてるからか、100で割るのを忘れてしまいます。。

Excel: 複数のExcelファイルのセルに値をまとめてセットするマクロを作りました

同じフォーマットのExcelファイルが複数あって、同じ場所のセルにまとめて更新したい時があります。

例えば、DBのテーブル定義書をテーブル単位にファイルを分けていて、各テーブルのラベルや物理名を特定のセルに入れる場合などがあると思います。

 

そんな時に使えるマクロを作りました。

こちらからダウンロードできます。

 

マクロの画面イメージ

f:id:crmprogrammer38:20170726135539p:plain

 

使い方は、対象のExcelファイル名(フルパス)、シート番号/シート名、セルアドレス、設定値をしておくとまとめてExcelを更新します。

Excelの列は次の通りです。

Excelファイル(フルパスで指定) 更新したいExcelファイルのフルパス
シート番号(1~) または、シート名 1から連番のシート番号、もしくはSheet1などのシート名
セル位置(例.A2など) セルのアドレス
設定値 設定したい値
処理結果 正常に実行できた場合は、"正常に書き込みました。"となり、
それ以外はエラーメッセージとなります。

 

Salesforce: 自動採番項目をupsertの外部ID(externalIdField)として使う

Salesforceで自動採番項目を外部IDにできるようになりました。

Apex内でupsertのキーとして使用できるようになりましたが、DataLoaderをGUIで使う時はupsertの外部IDとして選ぶことができません。

 

Help | Training | Salesforceの記載には、

データローダは ID 項目、あるいは、外部 ID 項目を API の Describe コマンドの結果より、
作成可能な、または、更新可能な項目を表示します。
しかしながら、自動採番の項目が作成可能、または、更新可能ではないので、データローダには表示されません。
これは、ユーザが潜在的な Insert エラーを実行しないようにするための意図的なものです。

 と書いてます。

 

ですが、DataLoaderのコマンドライン操作では、問題なくupsertの外部IDとして、自動採番項目が使えます。(もちろん、自動採番項目で登録されてない値でupsertするとエラーになります)

 

 

雑記: Java開発ではまった思い出(JDBCやlog4J)

久しぶりにJavaを使うことがありました。

だいぶ前に、JavaのWeb開発をしていてその時にはまったことをふと思い出しました。

 

WebLogicのDataSourceのConnectionをcloseしておらずエラー

インスタンスを起動してしばらくすると、DBのConnectionが取得できずエラーになる現象が発生していました。調べた結果、Connectionを最後にcloseしていないことが判明。

  Context ctx = null;
  Hashtable ht = new Hashtable();
  ht.put(Context.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory");
  ht.put(Context.PROVIDER_URL,"t3://hostname:port");
  Connection conn = null;

  try{ 
    ctx = new InitialContext(ht);
    javax.sql.DataSource ds = (javax.sql.DataSource) ctx.lookup ("myDataSource");
    conn = ds.getConnection();
  ・・・・・・ //途中の処理
    conn.close();  //必ず必要

絶対にcloseが必要ならWebLogic側でやってくれてもいいのになーと思いました。

 

WebLogicWebServiceでbooleanの引数にnullを指定されエラー

@WebMethod(operationName = "doSample")  
public Result doSample(
      @WebParam(name = "p1") String  p1, 
      @WebParam(name = "p2") boolean  p2
  ) {

こんなWebServiceを作成しました。

p2にnullを指定されるとWebLogicのエラーが呼び出し元に返ります。nullならfalseに変換してくれないのかと驚きました。

 

Log4jlog4j.propertiesの設定が正しく動かない

 ログが指定したファイルに書き出されず、何がいけないのかずっと調べていましたが、結局別のチームで作成したjarの中に別のlog4j.propertiesが含まれていてそちらが優先されていました。

アプリケーションでは、かなり多くのjarを含んでいて原因を特定するのは大変でした。jarの中身を確認する際に次を使ったのですがとても便利でした。

jd-gui

早くて使いやすいUIです。

 

今となっては懐かしい思い出ですが、当時は余裕がなくて大変だったなー。

Salesforce: 文字化けの制御で注意したいこと

他のシステムとの整合をとるため、Salesforceで入力できる文字を制限をかけたり、変換したい場合があります。

次のような要件があると思います。

  1. Shift_JISで定義されていない文字をエラーとしたい
  2. Shift_JISで定義されていない文字は、全角四角"□"に変換したい

※この例で、Shift_JISはCP932とします。

 

1の要件には次のようなコードが簡単です。

String convertbefore= 'a①bⅰc𠀋ef𠀋g'; //文字化けするか判定する文字

String charSet = 'Windows-31J';
String encodeStr = EncodingUtil.urlEncode(convertbefore,charSet);
String decodeStr = EncodingUtil.urlDecode(encodeStr, charSet);

if( convertbefore == decodeStr ) {
System.debug('文字化けする文字は無い');
} else {
System.debug('文字化けする文字が有る');
}

EncodingUtil.urlEncodeとurlDecodeで、文字化けする文字が「?」になるのを利用して、元の文字と比較することで、文字化けする文字列かどうかは判断できます。

ただ、この場合はどの文字が文字化けするかまではわかりません。

 

2の要件では、文字化けする文字まで特定する必要があります。この時にサロゲートペアの文字の対処が必要です。

サロゲートペアの文字でも、EncodingUtil.urlEncodeとurlDecodeで、文字化けする文字が「?」1文字となるのは変わりません。

String convertbefore= 'a①bⅰc𠀋ef𠀋g';

String charSet = 'Windows-31J';
String encodeStr = EncodingUtil.urlEncode(convertbefore,charSet);
String decodeStr = EncodingUtil.urlDecode(encodeStr, charSet);


Integer beforeidx = 0;
Integer decodeidx = 0;

String convertafter = '';

for( ; decodeidx < decodeStr.length() ;  ){


  String charval_before = '';
  if(    convertbefore.substring(beforeidx,beforeidx+1).codepointat(0) >= 55296
                && convertbefore.substring(beforeidx,beforeidx+1).codepointat(0) <= 56319 ){
    charval_before = convertbefore.substring(beforeidx , beforeidx+2);    
    beforeidx++;
  } else {
    charval_before = convertbefore.substring(beforeidx , beforeidx+1);
  }

  String charval_decode = decodeStr.substring(decodeidx, decodeidx + 1);

  if( charval_before == charval_decode ){
    convertafter += charval_before;
  } else {
    convertafter += '□';
  }

  beforeidx++;
  decodeidx++;
}

System.debug(convertafter);

 1文字ずつ同じかどうか見て、違った文字は文字化けした文字として扱い”□"に置き換えていますが、サロゲートペアの文字は、きちんと上位サロゲートと下位サロゲートで1文字として文字を作る必要があります。