月別アーカイブ: 2012年1月

雪は心を削る

今日もまたよく降る雪だ。

積った雪を毎日のように掻き出し、押し退け、捨てる。

この繰り返し。

でも次の日にはまた同じかそれ以上に積る。

元の木阿弥。

エンドレス。

なるほど、辛抱強い県民性を生むのも無理はない。

こんなにも自分のやったことが無意味に感じられるのはなかなか無い。

しかも、雪の相手をすると体力を相当に消耗する。

体力がなければ気力も湧いてこない。

 

雪は心を削る。

 

 

 

 

とか、テキトーに書き散らかしてみた。

排他エラーをハンドルする共通処理拡張メソッドを作ってみた

ASP.NET Webフォームアプリケーションを作成する際、楽観的排他制御を行うのが一般的です。

このとき、排他エラーを検知した際の処理を集約例外ハンドラーに任せてしまえば楽ですが、実際は「業務エラー」扱いとして再実行させたいケースもままあると思います。

 

そんな時に使える拡張メソッドを作ってみました。

 

public static class PageExtentions
{
  public static void HandleDbUpdateConcurrency(this Page page, Action action)
  {
    try
    {
      action();
    }
    catch (DbUpdateConcurrencyException)
    {
      var validator = new CustomValidator()
      {
        ErrorMessage = "",
        IsValid = false,
      };
      page.Validators.Add(validator);
    }
  }
}

 

この例ではEFの排他チェック例外をキャッチし、排他チェックエラーが発生した旨をCustomValidatorを追加することで、ValidationSummaryに表示します。

もちろん、プロジェクト共通の既定Webフォーム等を用意して、エラー領域に表示してもいいでしょう。

(主題とは外れますが、排他チェック例外って使用するデータアクセステクノロジーごとに違う例外になっちゃうから、ビジネスロジック層あたりで独自例外にWrapしてやるのが良さそうですね。)

 

使い方はこんな感じです。

 

protected void UpdateButton_Click(object sender, EventArgs e)
{
  Page.HandleDbUpdateConcurrency(() =>
  {
    var item = Session["OriginalItem"] as MyItem;
    item.Name = NameTextBox.Text;

    var logic = new MyItemLogic();
    logic.Update(item);
  });
}

 

引数なしのラムダ式で排他チェック例外が発生する処理を記載してやります。

 

色々な画面ですべてのコマンドボタンのイベントハンドラーにtry-catchを書くなんてのはナンセンスなので、こういった方法で共通化してみてはどうでしょうか。

また、自分はこうやってるとかあればぜひ教えてください。

Git:VSSの作業フォルダ用excludeファイル

もはやVSSは古き良き時代の遺物ですが、参加するプロジェクトによっては、未だにVSSを使用しなければならない時もあります。

 

そんな時は、作業コピーのフォルダにGitのリポジトリ―を作っちゃいましょう。そして、トピックブランチ作成→git commit * n→git rebase –i でまとめちゃって、VSSにチェックインってやれば、ストレスが少なく作業ができますね!

ただ、この時VSS用のファイルは世代管理したくないですよね。

 

そんなあなたは/.git/info/excludeファイルを編集し、次のようにしましょう。VSプロジェクト、VSS関連ファイルが、Git管理対象外になります。

# git ls-files –others –exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~
obj/
bin/
*.suo
*.user
*.scc
*.vssscc
*.vspscc
TestResults/

 

#このファイルはGistにもあげてあります→exclude file in VSS working folder — Gist

EF:Eager Loadのための型安全なInclude

Entity FrameworkのEntity Data Modelにはナビゲーション プロパティというものがあり、データベース上で外部キー制約がついていた場合、その外部キーに紐づくデータを取得できます。

通常、ナビゲーション プロパティはそのプロパティにアクセスされた際に初めてデータアクセスが発生します。(なお、これをLazy Loadといいます。)

 

しかし、必ずナビゲーション プロパティにアクセスすることが分かっている場合、一緒に読み込みを済ませておきたいケースもあります。(なお、これをEager Loadといいます。)

そんなときに使用するのが、Includeメソッドです。

Include メソッド

クエリの結果に含める関連オブジェクトを指定します。

しかし、Includeメソッドの引数は文字列で、タイプミスなどをすぐには検出できません。よく訓練されたC#erとしては、型安全に指定したいですよね?

 

というわけで、拡張メソッドとして作ってみました。

public static ObjectQuery<T> Include<T, V>(
  this ObjectQuery<T> query,
  Expression<Func<T, V>> expression)
{
  var memberExp = expression.Body as MemberExpression;
  if (memberExp == null)
  {
    throw new ArgumentException();
  }

  var entityName = memberExp.Member.Name;
  return query.Include(entityName);
}

 

使い方はシンプルで、次のようにラムダ式で指定します。

var context = new DatabaseEntities();
var persons = context.Persons.Include(x => x.Department);

 

本来は、引数に本当にナビゲーション プロパティを指定されているかどうかをチェックしたりも必要だと思いますが、とりあえずプロトタイプということで。

 

#Expressionからプロパティ名を取得する方法は、こちらの記事を参考にさせていただきました。

INotifyPropertyChanged の実装 « ++C++; // 未確認飛行 C ブログ

EF:連関エンティティはedmではアソシエーションとして表される

#元ネタはこちら→Entity Framework and ASP.NET – Getting Started Part 1: The Official Microsoft ASP.NET Site

 

例えば、以下のようなPersonとProjectの多対多の関係を表すために、PersonProjectという連関エンティティがあるとします。

image

 

この情報を元にEDMを生成すると、PersonProjectはアソシエーションとして定義されます。

image

image

image

image

image

 

EFってうまくできているんだなぁと思ったのでメモ。

ASP.NET:TextBox.TextはHTMLエンコードされるがLabel.TextはHTMLエンコードされない

MSDNライブラリにも明記されています。

TextBox.Text プロパティ

テキスト ボックスが表示されるとき、このプロパティの内容は HTML エンコードされます。 たとえば、このプロパティを "<b>Test</b>" に設定した場合、太字の "Test" ではなく "<b>Test</b>" がブラウザーに表示されます。

Label.Text プロパティ

Text プロパティには HTML を含めることができます。 そうである場合、HTML は未変更でブラウザーに渡されますが、ブラウザーでテキストではなくマークアップとして解釈されることがあります。 ブラウザーで HTML マークアップをプレーン テキストとして表示する場合は、クラス概要の例で示すように HtmlEncode メソッドを使用できます。

 

データバインド式を書くときなど、Label.TextプロパティはHttpUtility.HtmlEncodeメソッドを入れるのを忘れないようにしましょう。

aspx

<asp:Label ID="Label1" runat="server" Text='<%# HttpUtility.HtmlEncode("<s>hoge</s>") %>'></asp:Label>

実行結果

image

生成されたHTML

<span id="Span1">&lt;s&gt;hoge&lt;/s&gt;</span>

 

なお、TextBox.Textでも同じように書くと、HTMLエンコードが2回行われてしまいますのでご注意を。

aspx

<asp:TextBox ID="TextBox1" runat="server" Text='<%# HttpUtility.HtmlEncode("<s>hoge</s>") %>'></asp:TextBox>

実行結果

image

生成されたHTML

<input name="TextBox1" type="text" value="&amp;lt;s&amp;gt;hoge&amp;lt;/s&amp;gt;" id="Text1" />

 

でも、TextBoxとLabelで統一した書き方ができないのはちょっと気持ちが悪いですね・・・

C#でもMapBetween・改

C#でもMapBetween « be free

 

Zipメソッドを使うともっと簡単でした。

using System;
using System.Linq;
using System.Collections.Generic;

namespace ConsoleApplication1
{
    public static class EnumerableEx
    {
        public static IEnumerable<TResult> MapBetween<TValue, TResult>(this IEnumerable<TValue> source, Func<TValue, TValue, TResult> f)
        {
            return source
                .Zip(
                    source.Skip(1),
                    (x, y) => new { OldValue = x, NewValue = y })
                .Select(x => f(x.OldValue, x.NewValue));
        }
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            var q = new[] { 1, 2, 3, 4, 5 }.MapBetween((a, b) => a + b);
            foreach (var n in q)
            {
                Console.WriteLine(n);
            }
        }
    }
}

 

パク・・・参考にしたのは、MVP for Linqことneueccさんの以下のエントリ。

neue cc – Reactive Extensionsで前後の値を利用する

 

流石・・・流石すぎる!

#またしてもGistに上げました。