※この投稿はMicrosoft Visual Studio 2008 Beta2で動作を確認しています。
前回データを追加する方法について記述したあとで、追加したデータを削除する方法について述べてみようと考えていました。
データを削除するには、該当するデータのインスタンスを特定する必要があります。そこで追加した1件のデータを特定するための方法を考えていたところ、プログラムの記述方法がいくつかあることに気づきました。
その試行錯誤の経過をまとめておこうと思います。
最初は、一番最後にあるデータを特定するため、Lastメソッドが利用できないか、と考えて次のように記述してみました。
People deletePerson = dtc.People.Last();
しかしこの場合、実行時に"クエリ演算子 'Last' はサポートされていません。"というエラーになります。
記述方法をいくつか変えて試してみましたが、どの場合も同じ結果になったので、Lastメソッドは実際使えないのだと思われます。
次に、検索条件を指定してその中の一番最初のデータを取り出す、という方法を考えてみました。
using System;
using System.Linq;
namespace LINQ6
{
class Program
{
static void Main(string[] args)
{
LINQTESTDataContext dtc = new LINQTESTDataContext();
dtc.Log = Console.Out;
var query = from p in dtc.People
where p.Name == "オノ シュウジ"
select p;
People deletePerson = query.First();
Console.WriteLine("id={0}, 名前={1}, 性別={2}, 年齢={3}",
deletePerson.id, deletePerson.Name, deletePerson.Gender, deletePerson.Age);
Console.Read();
}
}
}
これで求めるデータを取り出すことができます。
結果は次のようになりました。
ここで生成されるSQL文を見ると、「SELECT TOP 1 …」となっています。プログラム中では2つのセンテンスに分けて書いているデータの取得とその中のデータの特定が、実際には1つのSQL文に置き換えられていることがわかります。
このような動作となるのは、LINQ to SQLでは実際にデータを取り出す動作をするときに、最適なSQL文を生成するという仕組みになっているためです。
さてここで、実際に発行されるSQL文が1つならプログラムも1行にまとめてしまいたい、という欲求から次のようにプログラムを修正してみました。
People deletePerson = (from p in dtc.People
where p.Name == "オノ シュウジ"
select p).First();
確かに2つのプログラムは1つにできていますが、その意図が伝わりにくいように思います。それで拡張メソッドをそのまま使う方法で記述しなおしてみました。
People deletePerson =
dtc.People.Where(p => p.Name == "オノ シュウジ").First();
だいぶ短くはなりましたが、それでもちょっともたついてる気がします。
実は次のような書き方ができました。
People deletePerson = dtc.People.First(p => p.Name == "オノ シュウジ");
これでも実行結果は同じになります。
この記述が一番すっきりしてますね。
プログラムが意図している内容もはっきり伝わるんじゃないでしょうか。
実はデータを1件取得するためにはFirstメソッドのほかにSingleというメソッドも使えます。
using System;
using System.Linq;
namespace LINQ6
{
class Program
{
static void Main(string[] args)
{
LINQTESTDataContext dtc = new LINQTESTDataContext();
dtc.Log = Console.Out;
People deletePerson = dtc.People.Single(p => p.Name == "オノ シュウジ");
Console.WriteLine("id={0}, 名前={1}, 性別={2}, 年齢={3}",
deletePerson.id, deletePerson.Name, deletePerson.Gender, deletePerson.Age);
Console.Read();
}
}
}
この場合結果は次のようになり、生成されるSQL文が異なってきます。
上記の結果だけを見るとFirstとSingleで同じように使えるように見えますが、Singleの場合、検索結果に複数のデータが含まれると実行時に"シーケンスに複数の要素が含まれています"というエラーが発生します。
主キーを指定して検索する、といったようにデータが確実に1件だけ取り出せるという場合にSingleを利用し、その他の場合はFirstを利用するべきかな、と今のところ考えています。