trapemiyaの日記

hatenablogが新しくなったんで新規一転また2019年1月からちょこちょこ書いてます。C#中心のプログラミングに関するお話です。

T4でコード生成の自動生成化を進めていて思うこと

ずーぅつとやってることなのだが、C#でコーディングする際に、T4というツールを使ってソースを生成する機能を進化させ続けている。
大体、事務的なプログラミングのパターンは決まっているので、比較的こういうことには事務用アプリの作成には向いている。

今は私はC#を用いてWPFでMVVMデザインパターンでそういったアプリを開発しているが、これに沿った独自のフレームワークを作成し、それに沿ったコードをT4で自動生成している。

単純にコーディングすれば良いところをT4で自動生成させることを開発しているのだから手間がかかる。でも、それは次からはちゃんと省力化につながっている。決まりきった画面ならパラメータをT4に与えるだけで一つもソースを直すことなく一通りの動作をする。そんなに簡単な画面ではなく、ちゃんと実用レベルに耐えれるぐらいの画面である。

もちろん、T4で自動生成するよりも時と場合によってはまるごとソースファイルをコピーし、それを修正した方が早いこともある。あまりにも似た画面の場合などだ。これは場合によって使い分けている。

で、こうやってT4で自動生成していくと、どうしてもT4に与えるパラメータが増えてくる。もっとも人間が管理できないほどは多くないのだが、今後増えることはあっても減ることはないだろう。
なので、ソースの自動生成に限界を感じる時がくるかもしれない。そんな時、AIが役に立たないかなぁと思ったりしている。

今のように論理的に毎回間違いなく同じ動作・処理をするプログラムというものは無くなることはないだろう。そういったものは必ず必要だからだ。人間は応用も効くが間違えてもしまう。なので、間違いを犯さないプログラミングは必要なのだ。もっと言えば、論理的なことは必ず論理的に動作するということは不変であり、無くなるわけがない。

なので、AIはAIとして自己判断するという分野の発展は求められていくだろうし、その一方で今のようなプログラミングはプログラミングとして求められ続けていくだろう。

であれば、T4の限界をAIによって突破できるかもしれないと考えてみたりする。こういうアプリを作ってという依頼をAIに渡せば、AIが作ってくれるのが理想である。どうアプローチすればそれが実現できるのか?
その意識は忘れないようにしようと思う。

プログラミングがプログラミングを生み出せるようになれば、さらにAIがプログラミングをするようになれば、そこから人間では到底できなかった思考が生まれ、科学は指数関数的に発展するのではないかと思う。反重力エンジンなんかもできちゃうんじゃないかな?大統一理論とか完成して。

確かにプログラミングは進化し続けていると思う。ただ、30年以上もCOBOLPASCALの頃からプログラミングを続けている僕から見れば、根本的なものは何も変わっていないと思う。やり方が変わっただけだ。

だから、オーセンティックでないものを求めてT4に手を出しているのかもしれない。あー、でも思い出した。30年前からそういう発想があったし、実際に僕もやっていて実用化してたんだ。COBOLでね。
なので、やっぱりAIが入らないと僕の中では何も変わってないように思っちゃうんだろうな。
こう書くとAIがプログラマに取って変わるように思うけど、じつはそうじゃなくてAIに教えるのは、そして指示を出すのはあくまで人間であって、そういう人間にはやっぱりシステム的な高度な知識が求められる。

#と、仕事の合間のコーヒーブレークに書きなぐってみました。これからの世界を担う若い世代に期待も込めて。

【SQL Server, SQL】削除フラグのあるテーブルの抽出条件 [初心者向けネタ]

あるレコードを表示したくなくて、削除フラグとか非表示フラグなんかが定義してあるレコードがよくあると思うんだが、そんなテーブルの抽出条件はcase句を使って以下のように簡単に書ける。
ちょっとしたTipsで知っている人も多いと思うが、意外に知らない人もいるようなので例を書いときます。

-- =============================================
-- Author:	BSS
-- Create date: 2020/01/25
-- Update date: 2020/01/25
-- Description:	部門を取得する。
-- =============================================
CREATE PROCEDURE [eigyou].[Get部門]
@削除除外	bit = 1	
AS
BEGIN

SET NOCOUNT ON;

select 部門ID, 部門名, 削除FLG
from dbo.部門
where 削除FLG = (case @削除除外 when 1 then 0 else 削除FLG end);
					
END

@削除除外が1だと削除フラグが0のレコードだけ抽出され、@削除除外が0だと削除フラグにかかわらず、全件抽出されます。
where 削除FLG = 削除FLG
という式を作っているところがポイントですね。

SQLからOracleサーバーへのリンクサーバーでwhere句の条件を変えるとなぜか結合する際のキーが一致しなくなる

SQL ServerからOracleをリンクサーバーにしてアクセスしているのだが、またまた不思議なことがあった。

以下のようなSQLを書いたのだが、なぜかユーザー名が表示されない。もちろんデータもあるし、SQLも間違いない。
実際、Oracle上で試したが問題なかった。

select us.ユーザー名
from EDPSTV..BSS.契約TBL t
left outer join EDPSTV..BSS.ユーザーTBL us on us.ユーザーID = t.ユーザーID
where t.契約コード = 'S2019122011'

上記で、Whereを付けなくて、top(10)のように指定した結果セットでは、ちゃんとユーザー名が表示される。
おかしなことに契約コードを変えるとちゃんとユーザー名が表示されるユーザーもいる。
全くわからなかったがユーザーIDがchar(20)だったので、join条件を以下のようにしたらうまく行った。

left outer join EDPSTV..BSS.ユーザーTBL us on us.ユーザーID + '                    ' = t.ユーザーID + '                    '

半角の空白20文字をそれぞれのユーザーIDの末尾に付加している。

おそらくOleDB辺りがOracleSQLを投げる際に変換しているのだと思うが、それが実際のユーザーIDの値によって揺れているってこと
なんかじゃないかと思う。
とうわけで、この調査に3時間もかかってしまった・・・

SQL ServerからOracleへのリンクサーバーでbitは使えない!?

SQL ServerからOracleのリンクサーバーへ以下のストアドプロシージャを実行したところ、

 

EXEC sp_executesql @sqlwk, N'@タイム抽出 bit,@抽出期間開始 char(8), @抽出期間終了 char(8), ・・・・・・・

 

以下のエラーが表示された。

 
リンク サーバー "HogeServer" の OLE DB プロバイダー "OraOLEDB.Oracle" から、メッセージ "" が返されました。
メッセージ 7320、レベル 16、状態 2、行 1
リンク サーバー "HogeServer" の OLE DB プロバイダー "OraOLEDB.Oracle" に対するクエリ
 "SELECT "Tbl1004"."fugaコード" "Col1112","Tbl1004"."moge区分" "Col1114",
       ・
       ・
       ・
   FROM "BSS"."契約TBL" "Tbl1004" WHERE (1)=? AND "Tbl1004"."契約開始日"<=? AND "Tbl1004"."契約終了日">=? ORDER BY "Col1115" ASC"
    を実行できません。
 
いろいろテストしてみるに、bitがダメみたい・・・
とりあえず tinyint で逃げた。
 
大体は問題ないけど、ちょこちょこ引っかかるなぁ
 

デスクトップを暗号化したら解除できない罠

デスクトップにファイルを作成すると、なんでもかんでもアイコンの右上に鍵のマークが表示される現象が発生したとヘルプを求められる。

調べてみると、デスクトップフォルダの「内容を暗号化してデータをセキュリティで保護する」チェックを外せば良いのだが、これが外せない。外そうとするとエラーが発生する。
結構有名らしいが、原因はexplorer.exeが常に掴んでいるからであった。
なので、他のユーザーでログインして変更しようとしたが、暗号化したユーザーじゃなきゃ解除させないよと叱られる・・・

仕方がないので、以下のバッチを作って実行し、無事に外すことに成功した。
なんだかなぁ~

taskkill /f /im explorer.exe
cipher /D %userprofile%\desktop
start explorer.exe

SQL Server Management Studio クエリーウインドウのタブを切り替えた際にウインドウの内容が更新されないことがある場合の対処方法

新しいPCにSQL Server Management Studio (SSMS)のv.18.4を入れて初めて使ってみたのがだが、クエリウインドウのタブを切り替えた際に、たまに画面が更新(リフレッシュ)されないことがある。
ググると、

SQL Management Studio 18 Screen Refresh Problem

https://feedback.azure.com/forums/908035-sql-server/suggestions/37820356-sql-management-studio-18-screen-refresh-problem

がヒットし、そこに書いてあった内容を参考にして、私の場合、

ツール → オプション → 環境 → 全般 → 視覚効果 で、
「可能ならハードウエアのグラフィックス アクセラレータを使用する」のチェックを外したところ、上記の不具合が解消された。

 

Windows FormプロジェクトにWPFプロジェクトで開発して機能を追加する

Window Formプロジェクトのアプリがあり、それに機能を追加する案件が発生しました。今更Windows Formで開発したくもなく、かといってWPFプロジェクトで全て作り直すのもアホらしいのです。
で、新規開発はWPFプロジェクトで作成し、それをWindows Formプロジェクトと合体させ、ユーザーから見ればシームレスに見えるように開発することにしました。
いろいろ試したところ、WPFプロジェクトを新しく作成し、そこからWindows Formプロジェクトを参照登録し、WPFプロジェクトからWindows Formプロジェクトの初期画面を表示するようにするとうまく行きました。といってもちょっとしたコツが要りますので、それを書いておきます。

まず、ダミーのWPFプロジェクトを作成し、そのApp.xamlのビルドアクションをApplicationDifinitionからPageにしてMainメソッドの自動生成を止め、App.xaml.csのAppクラスにMainメソッドを追加し、以下のようにWindows FormアプリケーションのMainメソッドを呼べば、Windows Formの初期画面が開きます。AppクラスのInitializeComponentメソッドを実行する必要があるようです。
参照設定としては、Windows FormプロジェクトとSystem.Windows.Formsが必要です。また、App.xamlからStartupUri="MainWindow.xaml"を削除する必要があります。

[STAThread]
public static void Main()
{
    App app = new App();
   //app.StartupUri = new Uri("MainWindow.xaml", UriKind.Relative);
   app.InitializeComponent();
   //app.Run();
   hoge.fuga.Main(null);
}

ここで注意が必要なのが、Windows FormアプリからWPFアプリの画面を開いて閉じると、そこでWPFのアプリが終わってしまいます。よって、次にWPFの画面を開こうとするとこけます。
結局、画面を閉じないようにしなければダメっぽいので、

[STAThread]
public static void Main()
{
   App app = new App();
   app.StartupUri = new Uri("MainWindow.xaml", UriKind.Relative);
   app.InitializeComponent();
   //app.Run();
   hoge.fuga.Main(null);
}

とし、

public MainWindow()
{
   InitializeComponent();
   this.Visibility = Visibility.Hidden;
}

として、MainWindowを非表示にして残し続けてやれば良いようである。