【C#】ReactivePropertyをModelで使う場合の留意点
ReactivePropertyはViewModelで使われている事が多い気がしていました。
そこでModelでもバンバン使っちゃって良いのでは...と思っていたところ、管理者の@okazukiさんからアドバイスいただきました。
@Einherjar1632 RPはUIスレッドでPropertyChangedを発行するというModel的にはちょっと余計なお世話してくれるところがあるので、そこだけ留意していただければいいと思います
— かずき@darui (@okazuki) December 26, 2015
デフォルトでUIスレッドですが、ISchedulerを引数にするオーバーロードがあるので、指定することもできるみたいです。
【C#】ReactivePropertyのReactiveCollectionについて
ここのところ、せこせこReactiveProperty
を勉強中なのでそのメモを記載します。
※RPの詳細は当該ライブラリ管理者のかずきさんブログを参考にするのが一番です。
blog.okazuki.jp
UIコントロールにObservableCollection
をバインドしていた場合当該コレクションに対してUIスレッド以外から要素の操作をすると例外を吐きます。
が、ObservableCollection
を継承しているReactiveProperty
のReactiveCollection
を用いると、同じような使い方でUIスレッドで要素の操作が可能になります。
※コンストラクタでUIスレッド以外も指定できそうです。
namespace DiffBetweenObservableCollectionAndReactiveCollection { class MainWindowViewModel { public ReactiveCollection<string> reactiveCollection { get; private set; } public ObservableCollection<string> observableCollection { get; private set; } public MainWindowViewModel() { observableCollection = new ObservableCollection<string>(); reactiveCollection = new ReactiveCollection<string>(); } public void AddObservableCollection() { Task.Run(() => { for (int i = 0; i < 10; i++) { this.observableCollection.Add(i.ToString()); } }); } public void AddReactiveCollection() { Task.Run(() => { for (int i = 0; i < 10; i++) { this.reactiveCollection.AddOnScheduler(i.ToString()); } }); } } }
上記のようにViewModel
にバインドしているObservableCollection
にAddするとNotSupportedException
をはきますが、ReactiveCollection
のAddOnScheduler
を使用すれば楽にUIスレッド以外から要素の追加ができました。
Githubにも上げました。
【Xamarin】Xamarin.FormsでMySQLに直接接続する
とても需要がなさそうなタイトルですね。
要はクラサバです。
通常であればApp⇔WebAPI⇔DBとやる流れのところを
App⇔DBの直繋ぎでやってしまおうという試みです。
この手法自体は一般的に見れば悪手です。
というより絶対にやるべきではありません。
しかしながら、社内の業務システムにおいて、比較的小規模かつPrivateな環境であれば
わざわざWebAPIを立てるのもコストになる為、そういう時には直繋ぎでやってしまっても良いのではないかということで試してみました。
開発環境は以下の通りです。
・Windows10Pro
・VisualStudio2015Community
・Xamarin.Forms4.0
・MySQL5.6
また私自身がXamarinAccount
をiOS
しか持っていませんので
ソリューション作成直後にAndroid
(WP
も)プロジェクトは速攻削除しています。
恐らくどれでも動く気もするのですが検証はしておりません。
プロジェクト作成
まずは新規でXamarin.Forms Shared
プロジェクトを作成します。
Xamarin.Forms Portable
もありますが、複数の環境で扱える特性上Shared
と比べ使用できる.NET Framework
が限定されます。
MySQL
への接続はSystem.Data
名前空間へのアクセスが必須になりますのでこちらを選択下さい。
各種dllを参照させる
下記から取得しましょう。
MySQL Plugin / Components / Xamarin
解凍しlib\ios\MySql.Data.CF.dll
をiOS
のプロジェクトに参照させます。
その際、System.Data
とI18N.West
のアセンブリも参照させましょう。
謎の後者については後述しますがバグ回避用です。
実装コード
Shared
プロジェクトに以下Forms Xaml Page
を追加します。
xamlには以下を記述し
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="XamarinFormsMySQL.XamarinFormsMySQLPage"> <Label Text="{Binding MainText}" VerticalOptions="Center" HorizontalOptions="Center" /> <StackLayout Padding="10,0"> <Label x:Name="LblMsg" Text="MySQL" VerticalOptions="CenterAndExpand" HorizontalOptions="Center" /> <Button x:Name="BtnConnect" Clicked="OnButtonClicked" FontSize="24" Text="XamarinMySQLTest" VerticalOptions="CenterAndExpand" HorizontalOptions="Center" /> </StackLayout> </ContentPage>
コードビハインドに以下を記述します。
謎のおまじないnew CP1250();
がありますが、バグ回避のためです。
MySQL
のdll
で設定されている文字セットはデフォルトでCP1250
ですが、Xamarinだと何故か認識できないみたいです。
using System; using MySql.Data.MySqlClient; using Xamarin.Forms; using I18N.West; namespace XamarinFormsMySQL { public partial class XamarinFormsMySQLPage : ContentPage { public XamarinFormsMySQLPage () { InitializeComponent (); } public void OnButtonClicked(object sender, EventArgs args) { try { new CP1250(); var cs = string.Format("Server=YourIPAddress;Port=3306;database=YourDatabase;User Id=YourID;Password=YourPassword;charset=utf8"); using(var db = new MySqlConnection(cs)) { db.Open(); var queryString = "select hello from helloxamarin"; var sqlcmd = new MySqlCommand(queryString, db); var result = sqlcmd.ExecuteScalar().ToString(); LblMsg.Text = result; db.Close(); } } catch (Exception ex) { LblMsg.Text = ex.ToString(); } } } }
あとはApp.cs
から追加したxamlを呼ぶようにして終わりです。
using Xamarin.Forms; namespace XamarinFormsMySQL { public class App : Application { public App () { MainPage = new XamarinFormsMySQLPage(); } } }
デバッグしてみる
MySQL
には予めtest
スキーマを作りhello
カラムを持ったhelloxamarin
テーブルを作成しておきました。
hello
カラムの中身はHelloXamarinMySQL
です。
比較的お手軽簡単にいきましたね。
あと私の環境ですと、何故かアイコンがビルド時にコピーできないようでビルドエラーが出ましたので、iOS
プロジェクトのResources
フォルダの画像は削除しました。
以下、Githubにも上げてあります。
github.com
【AWS】Windows環境でオンプレVMをAWSのEC2にインポート(移行)する
元ネタはクラメソさんのこれです。
クラメソさんのだとEC2 API Toolの利用がMacからだったので
Windows環境だとどうするかのメモ的なものになります。
といってもやる事は殆ど変わっていません。
仮想マシンをOVF形式でエクスポートするところまでは一緒ですので
・vmdkファイルはある前提です。
・S3のバケットも作っておいて下さい。
・EC2 API Toolは以下の「Download the Amazon EC2 API Tools」から落とせます。
Amazon EC2 API Tools : Developer Tools : Amazon Web Services
おもむろにcmdを開きましてToolsのパスを設定
PATH=C:\Program Files\Amazon\ec2-api-tools-1.7.5.1\bin\
EC2_HOMEとJAVA_HOMEの設定(しないと後々出てくるec2-import-instanceで怒られる)
SET EC2_HOME=C:\Program Files\Amazon\ec2-api-tools-1.7.5.1 SET JAVA_HOME=C:\Program Files\Java\jdk1.7.0_51
S3へのアクセスキーとシークレットキーを設定
SET AWS_ACCESS_KEY=アクセスキー SET AWS_SECRET_KEY=シークレットキー
リージョンの設定(以下はアジアパシフィック東京)
SET EC2_URL=https://ec2.ap-northeast-1.amazonaws.com
プロキシの設定
SET EC2_JVM_ARGS=-Dhttp.proxySet=true -Dhttps.proxySet=true -Dhttp.proxyHost=XX.XX.XX.XX -Dhttp.proxyPort=XX -Dhttps.proxyHost=XX.XX.XX.XX -Dhttps.proxyPort=XX
で、以下のコマンドでvmdkファイルからEC2作成
ec2-import-instance C:\disk1.vmdk -f VMDK -t t2.micro -a i386 -b einherjar1632-bucket -o アクセスキー -w シークレットキー -p Linux --subnet subnet-XXXXXXXX --private-ip-address XX.XX.XX.XX -z ap-northeast-1a
-t:EC2のインスタンスタイプを設定
-a:32bitOSなら「i386」を、64bitOSなら「x86_64」を設定
-b:S3のバケットを設定
-p:Windows環境の場合は「Windows」にして下さい。
--subnet:EC2に指定するサブネットを設定
--private-ip-address:EC2に適用するIPを設定
以下コマンドを実行し、Completeとなってたら出来ていると思います。
ec2-describe-conversion-tasks
S3にアップされてからEC2化するまで暫く時間がかかるので、定期的に実行して確認すると良いです。
無事EC2ができたらS3の中身は邪魔ですので消しておきましょう。
【Oracle】ダイレクトパスリード (Direct Path Read) について
ダイレクトパスリードとはバッファキャッシュを経由しないSELECTの事。
この事から直接ストレージからデータを引っ張ってくるため
当然ながらDBサーバのI/Oは高くなります。
これはパラレルクエリを使用した場合になりやすく
またチューニング・速度改善の観点としてパラレルクエリで小さいテーブルを処理させる場合は
バッファキャッシュ上に十分データをキャッシュする事も出来るため
かえって遅くなる事もあります。
逆に大規模なテーブルに対してのパラレルクエリは
そもそもバッファキャッシュキープ出来きない事が懸念される(キャッシュできるデータ量を超えている事が多いため)ため
I/Oを発生させてでもパラレル化し
ダイレクトパスリードさせる事をおすすめします。
尚、パラレルクエリのバッファキャッシュキープが出来ない件ですが
Oracle11gからは、インメモリパラレルクエリ(In-Memory Parallel Query)の設定が出来るため
パラレルでもバッファキャッシュを用いる事が出来ます。
ただしインメモリパラレルクエリには注意点があって
この機能を有効化する場合は
・自動パラレル度決定
・パラレルキューイング
も同時に設定されてしまいます。
特にチューニング・速度改善の観点からはパラレルキューイングが厄介で
要するにSQLが発行されたタイミングで十分なパラレルサーバが無い場合はキューに入れられて
条件が満たされた時にはじめてデキューされる事(このタイミングで処理される)
により返って遅くなってしまう場合もあります。
【Oracle】遅いSQLを特定するSQL
ブログの移設ついでに過去のブログ内容を投稿。
DBAであればOEMでSQL監視から特定してみたり
AWRレポートを発行したり等でどのSQLがボトルネックになっているかを調査する事が出来ますが
開発者サイドに立った場合になかなかこういったところまで踏み込む事は難しいと思います。
そもそもちゃんとした会社であれば実装部隊とチューニング部隊とが分かれている(と聞かされている)ため
携わる機会すら無いかもしれません。
そういった場合を考慮しSQL1発で取得出来るクエリを作成しました。
SELECT DISTINCT S.SID , S.STATUS , S.PROGRAM , q.MODULE , q.SQL_ID , dbms_lob.substr(q.SQL_FULLTEXT,3000,1 ) SQL , s.LAST_CALL_ET 実行時間 , q.PARSING_SCHEMA_NAME , q.FIRST_LOAD_TIME , q.LAST_LOAD_TIME , s.OSUSER , S.MACHINE FROM v$session s , v$sql q WHERE s.SQL_ID = q.SQL_ID --↓ここの数字を変えます。このサンプルでは10秒以上実行され続けているSQLを特定 AND s.LAST_CALL_ET > 10 --↑ここの数字を変えます。このサンプルでは10秒以上実行され続けているSQLを特定 AND q.PARSING_SCHEMA_NAME <> 'SYSMAN' --↓使用する開発環境ソフトウェアは除外すると見やすいかも AND NOT q.MODULE IN ('cse.exe','osqledit.exe','ob10.exe') --↑使用する開発環境ソフトウェアは除外すると見やすいかも AND S.STATUS = 'ACTIVE' ORDER BY 1
V$SESSIONとV$SQLへの参照が必要ですので、
これらは必要なロールを付与する等で対応して下さい。
上記のサンプルでは10秒以上実行され続けているSQLを特定します。
私は開発環境ソフトウェアに関して
・CSE
・ObjectBrowser
・OSqlEdit
を使い分けて使用していますので
これらから発行されたSQLは対象として引っかからないように除外してあります。
このSQLは現在実行されているものにスポットが当たりますので
例えば監視アプリやバッチ等で何分かおきに発行するように組み込む事により
実行に時間がかかっているSQLの特定が可能となります。
これで後は該当SQLの実行計画を見るなりして
速度改善・パフォーマンスチューニングに繋げれます。