VisualStudio2008より追加された便利で強力な機能
統合言語クエリ (LINQ : Language Integrated Query)
ちょっと使ってみると、意外と難しいし、テクニック的にも奥が深いものです。
関数型言語にしかないような機能ラムダ式(Lambda式)などはオブジェクト指向とは一味違う機能です。
DataBaseの操作にも、Xmlの操作にも、さらにもっと単純な配列なコンテナにさえ機能する
言語共通・高汎用な統合言語クエリを皆で一緒にマターリ勉強しましょう。
質問、便利なマイテクニックの発表、いろいろやっちゃってください。
探検
【VB.NET】LINQ友の会【C#, C♯, C#】
■ このスレッドは過去ログ倉庫に格納されています
1デフォルトの名無しさん
2008/02/09(土) 23:51:342デフォルトの名無しさん
2008/02/09(土) 23:52:34 >>1 もこれから使い始めます、答えられそうな質問にはどんどん答えます、無理なのは……誰かお願い。
2008/02/10(日) 00:05:21
まずは一発目
LINQってなあに、という所で、これは以下のような事ができます。
このコードは配列から4以下の値を取り出します。
int [] data = new int[] { 3, 1, 4, 1, 5, 9, 2, 6 };
IEnumerable<int> x = from s in data where s <= 4 select s;
foreach (int ite in x)
System.Console.Write( "{0}," , ite);
3,1,4,1,2,
これを、ちょっと短くしてみる。
int [] data = new int[] { 3, 1, 4, 1, 5, 9, 2, 6 };
foreach (int ite in from s in data where s <= 4 select s)
System.Console.Write( "{0}," , ite);
とてもすっきりかけます。
LINQってなあに、という所で、これは以下のような事ができます。
このコードは配列から4以下の値を取り出します。
int [] data = new int[] { 3, 1, 4, 1, 5, 9, 2, 6 };
IEnumerable<int> x = from s in data where s <= 4 select s;
foreach (int ite in x)
System.Console.Write( "{0}," , ite);
3,1,4,1,2,
これを、ちょっと短くしてみる。
int [] data = new int[] { 3, 1, 4, 1, 5, 9, 2, 6 };
foreach (int ite in from s in data where s <= 4 select s)
System.Console.Write( "{0}," , ite);
とてもすっきりかけます。
2008/02/10(日) 00:20:06
部分的にSQLがかけますよ、って感じか
どーなんだろ、便利か?これ
どーなんだろ、便利か?これ
2008/02/10(日) 00:25:18
まあ、便利なんだろうけど、あまり優秀でないプログラマに使わせるとこんな記述が
そこらじゅうにばら撒かれたきわめて保守し辛いプログラムが量産されるような気が
する。
そこらじゅうにばら撒かれたきわめて保守し辛いプログラムが量産されるような気が
する。
2008/02/10(日) 00:34:33
もう全部の言語合体したのを作っちゃいなよw
CLR自体に新しい何かが加わったの?
.NET層のインターフェイス?
シンタックスシュガーにも見えなくもない。
全然c#に触れてないので見当違いなこと言ってたらごめんよ。
CLR自体に新しい何かが加わったの?
.NET層のインターフェイス?
シンタックスシュガーにも見えなくもない。
全然c#に触れてないので見当違いなこと言ってたらごめんよ。
2008/02/10(日) 00:53:14
>>6
ラムダ式のシンタックスシュガーですよ、かなりなんでも出来ます。
ラムダ式のシンタックスシュガーですよ、かなりなんでも出来ます。
2008/02/10(日) 00:55:57
明日は、とりあえず難しい事考えなくても、簡単に使えるサンプルでも考えてみるかな・・・
2008/02/10(日) 01:15:38
洋書だとC#3の本がかなり出てるらしいけど、日本語のはぜんぜんでないな。
2008/02/10(日) 07:20:46
何が便利かって、グループ化の機能が便利だ。
11762
2008/02/10(日) 12:42:26 static T Multiply<T>(T left, T right) {
var r = Expression.Parameter(typeof(T), "left");
var l = Expression.Parameter(typeof(T), "right");
return Expression.Lambda<Func<T, T, T>>(Expression.Multiply(r, l), l, r).Compile()(left, right);
}
Expression Treeで遊んでみた
var r = Expression.Parameter(typeof(T), "left");
var l = Expression.Parameter(typeof(T), "right");
return Expression.Lambda<Func<T, T, T>>(Expression.Multiply(r, l), l, r).Compile()(left, right);
}
Expression Treeで遊んでみた
2008/02/11(月) 15:15:26
データベースからデータを拾ってきて、LocationID が 10 未満の行を取り出すサンプル。
従来コードから徐々に LINQ に書き換えて行って見ました。
データは、Microsoft SQL Server 2005 に最初から入っているものです。
こちらの使用環境は Professional エデッションで、二枚付いているディスクはフルインストール
ウインドウズ認証でインストールして特に変わった設定がしてなければ、"貴方のPC" を自分のPC名に書き換えれば動くと思います、多分。
データベースは、最初から入っているサンプルデータ AdventureWorks の中の Location(Production) を使ってみました。
DataGridView コントロールを二つ貼り付けて、ボタンを一つ用意して、ボタンプッシュのイベントで実行しています。
従来コードから徐々に LINQ に書き換えて行って見ました。
データは、Microsoft SQL Server 2005 に最初から入っているものです。
こちらの使用環境は Professional エデッションで、二枚付いているディスクはフルインストール
ウインドウズ認証でインストールして特に変わった設定がしてなければ、"貴方のPC" を自分のPC名に書き換えれば動くと思います、多分。
データベースは、最初から入っているサンプルデータ AdventureWorks の中の Location(Production) を使ってみました。
DataGridView コントロールを二つ貼り付けて、ボタンを一つ用意して、ボタンプッシュのイベントで実行しています。
2008/02/11(月) 15:16:32
続き(>>12)
次のように変換されます。
1 Tool Crib 0.0000 0.00 1998/06/01
2 Sheet Metal Racks 0.0000 0.00 1998/06/01
3 Paint Shop 0.0000 0.00 1998/06/01
4 Paint Storage 0.0000 0.00 1998/06/01
5 Metal Storage 0.0000 0.00 1998/06/01
6 Miscellaneous Storage 0.0000 0.00 1998/06/01
7 Finished Goods Storage 0.0000 0.00 1998/06/01
10 Frame Forming 22.5000 96.00 1998/06/01
20 Frame Welding 25.0000 108.00 1998/06/01
30 Debur and Polish 14.5000 120.00 1998/06/01
40 Paint 15.7500 120.00 1998/06/01
45 Specialized Paint 18.0000 80.00 1998/06/01
50 Subassembly 12.2500 120.00 1998/06/01
60 Final Assembly 12.2500 120.00 1998/06/01
↓
1 Tool Crib 0.0000 0.00 1998/06/01
2 Sheet Metal Racks 0.0000 0.00 1998/06/01
3 Paint Shop 0.0000 0.00 1998/06/01
4 Paint Storage 0.0000 0.00 1998/06/01
5 Metal Storage 0.0000 0.00 1998/06/01
6 Miscellaneous Storage 0.0000 0.00 1998/06/01
7 Finished Goods Storage 0.0000 0.00 1998/06/01
次のように変換されます。
1 Tool Crib 0.0000 0.00 1998/06/01
2 Sheet Metal Racks 0.0000 0.00 1998/06/01
3 Paint Shop 0.0000 0.00 1998/06/01
4 Paint Storage 0.0000 0.00 1998/06/01
5 Metal Storage 0.0000 0.00 1998/06/01
6 Miscellaneous Storage 0.0000 0.00 1998/06/01
7 Finished Goods Storage 0.0000 0.00 1998/06/01
10 Frame Forming 22.5000 96.00 1998/06/01
20 Frame Welding 25.0000 108.00 1998/06/01
30 Debur and Polish 14.5000 120.00 1998/06/01
40 Paint 15.7500 120.00 1998/06/01
45 Specialized Paint 18.0000 80.00 1998/06/01
50 Subassembly 12.2500 120.00 1998/06/01
60 Final Assembly 12.2500 120.00 1998/06/01
↓
1 Tool Crib 0.0000 0.00 1998/06/01
2 Sheet Metal Racks 0.0000 0.00 1998/06/01
3 Paint Shop 0.0000 0.00 1998/06/01
4 Paint Storage 0.0000 0.00 1998/06/01
5 Metal Storage 0.0000 0.00 1998/06/01
6 Miscellaneous Storage 0.0000 0.00 1998/06/01
7 Finished Goods Storage 0.0000 0.00 1998/06/01
2008/02/11(月) 15:17:26
続き(>>13)
// 従来方式
private void Test4()
{
using (System.Data.SqlClient.SqlDataAdapter myDataAdapter = new System.Data.SqlClient.SqlDataAdapter("select * from Production.Location", "Data Source=貴方のPC;Initial Catalog=AdventureWorks;Integrated Security=True"))
{
// サンプルデータベースからデータを取り込む
System.Data.DataTable dataTable1 = new System.Data.DataTable();
myDataAdapter.Fill(dataTable1);
// LocationIDが10以下の行のみのテーブルを作る
System.Data.DataTable dataTable2 = dataTable1.Clone();
foreach (System.Data.DataRow tmp1 in dataTable1.Select("LocationID < 10"))
{
System.Data.DataRow tmp2 = dataTable2.NewRow();
tmp2.ItemArray = tmp1.ItemArray;
dataTable2.Rows.Add(tmp2);
}
// ためしに表示
this.dataGridView1.DataSource = dataTable1;
this.dataGridView2.DataSource = dataTable2;
}
}
// 従来方式
private void Test4()
{
using (System.Data.SqlClient.SqlDataAdapter myDataAdapter = new System.Data.SqlClient.SqlDataAdapter("select * from Production.Location", "Data Source=貴方のPC;Initial Catalog=AdventureWorks;Integrated Security=True"))
{
// サンプルデータベースからデータを取り込む
System.Data.DataTable dataTable1 = new System.Data.DataTable();
myDataAdapter.Fill(dataTable1);
// LocationIDが10以下の行のみのテーブルを作る
System.Data.DataTable dataTable2 = dataTable1.Clone();
foreach (System.Data.DataRow tmp1 in dataTable1.Select("LocationID < 10"))
{
System.Data.DataRow tmp2 = dataTable2.NewRow();
tmp2.ItemArray = tmp1.ItemArray;
dataTable2.Rows.Add(tmp2);
}
// ためしに表示
this.dataGridView1.DataSource = dataTable1;
this.dataGridView2.DataSource = dataTable2;
}
}
2008/02/11(月) 15:18:11
続き(>>14)
// var を使ったバージョン
private void test5()
{
using (var myDataAdapter = new System.Data.SqlClient.SqlDataAdapter("select * from Production.Location", "Data Source=貴方のPC;Initial Catalog=AdventureWorks;Integrated Security=True"))
{
// サンプルデータベースからデータを取り込む
var dataTable1 = new System.Data.DataTable();
myDataAdapter.Fill(dataTable1);
// LocationIDが10以下の行のみのテーブルを作る
var dataTable2 = dataTable1.Clone();
foreach (var tmp1 in dataTable1.Select("LocationID < 10"))
{
var tmp2 = dataTable2.NewRow();
tmp2.ItemArray = tmp1.ItemArray;
dataTable2.Rows.Add(tmp2);
}
// ためしに表示
this.dataGridView1.DataSource = dataTable1;
this.dataGridView2.DataSource = dataTable2;
}
}
// var を使ったバージョン
private void test5()
{
using (var myDataAdapter = new System.Data.SqlClient.SqlDataAdapter("select * from Production.Location", "Data Source=貴方のPC;Initial Catalog=AdventureWorks;Integrated Security=True"))
{
// サンプルデータベースからデータを取り込む
var dataTable1 = new System.Data.DataTable();
myDataAdapter.Fill(dataTable1);
// LocationIDが10以下の行のみのテーブルを作る
var dataTable2 = dataTable1.Clone();
foreach (var tmp1 in dataTable1.Select("LocationID < 10"))
{
var tmp2 = dataTable2.NewRow();
tmp2.ItemArray = tmp1.ItemArray;
dataTable2.Rows.Add(tmp2);
}
// ためしに表示
this.dataGridView1.DataSource = dataTable1;
this.dataGridView2.DataSource = dataTable2;
}
}
2008/02/11(月) 15:19:25
続き(>>15)
// LINQ を使ったバージョン(意味が解りやすいように型付き)
private void Test7()
{
using (System.Data.SqlClient.SqlDataAdapter myDataAdapter = new System.Data.SqlClient.SqlDataAdapter("select * from Production.Location", "Data Source=貴方のPC;Initial Catalog=AdventureWorks;Integrated Security=True"))
{
// サンプルデータベースからデータを取り込む
System.Data.DataTable dataTable1 = new System.Data.DataTable();
myDataAdapter.Fill(dataTable1);
// LocationIDが10以下の行のみのテーブルを作る
EnumerableRowCollection<System.Data.DataRow> query = from tmp2 in dataTable1.AsEnumerable() where tmp2.Field<short>("LocationID") < 10 select tmp2;
System.Data.DataTable dataTable2 = query.CopyToDataTable();
// ためしに表示
this.dataGridView1.DataSource = dataTable1;
this.dataGridView2.DataSource = dataTable2;
}
}
// LINQ を使ったバージョン(意味が解りやすいように型付き)
private void Test7()
{
using (System.Data.SqlClient.SqlDataAdapter myDataAdapter = new System.Data.SqlClient.SqlDataAdapter("select * from Production.Location", "Data Source=貴方のPC;Initial Catalog=AdventureWorks;Integrated Security=True"))
{
// サンプルデータベースからデータを取り込む
System.Data.DataTable dataTable1 = new System.Data.DataTable();
myDataAdapter.Fill(dataTable1);
// LocationIDが10以下の行のみのテーブルを作る
EnumerableRowCollection<System.Data.DataRow> query = from tmp2 in dataTable1.AsEnumerable() where tmp2.Field<short>("LocationID") < 10 select tmp2;
System.Data.DataTable dataTable2 = query.CopyToDataTable();
// ためしに表示
this.dataGridView1.DataSource = dataTable1;
this.dataGridView2.DataSource = dataTable2;
}
}
17デフォルトの名無しさん
2008/02/11(月) 15:25:03 続き(>>16) 最後
// LINQ を使ったバージョン
private void Test8()
{
using (var myDataAdapter = new System.Data.SqlClient.SqlDataAdapter("select * from Production.Location", "Data Source=貴方のPC;Initial Catalog=AdventureWorks;Integrated Security=True"))
{
// サンプルデータベースからデータを取り込む
var dataTable1 = new System.Data.DataTable();
myDataAdapter.Fill(dataTable1);
// LocationIDが10以下の行のみのテーブルを作る
var tmp1 = from tmp2 in dataTable1.AsEnumerable() where tmp2.Field<short>("LocationID") < 10 select tmp2;
var dataTable2 = tmp1.CopyToDataTable();
// ためしに表示
this.dataGridView1.DataSource = dataTable1;
this.dataGridView2.DataSource = dataTable2;
}
}
// LINQ を使ったバージョン
private void Test8()
{
using (var myDataAdapter = new System.Data.SqlClient.SqlDataAdapter("select * from Production.Location", "Data Source=貴方のPC;Initial Catalog=AdventureWorks;Integrated Security=True"))
{
// サンプルデータベースからデータを取り込む
var dataTable1 = new System.Data.DataTable();
myDataAdapter.Fill(dataTable1);
// LocationIDが10以下の行のみのテーブルを作る
var tmp1 = from tmp2 in dataTable1.AsEnumerable() where tmp2.Field<short>("LocationID") < 10 select tmp2;
var dataTable2 = tmp1.CopyToDataTable();
// ためしに表示
this.dataGridView1.DataSource = dataTable1;
this.dataGridView2.DataSource = dataTable2;
}
}
2008/02/11(月) 15:28:13
さて、次はLINQ to Sql にいくか、それともしょうもない内容にすべか
誰も来なければそろそろ諦めるかw
誰も来なければそろそろ諦めるかw
2008/02/11(月) 17:33:56
LINQ: .NET 統合言語クエリ
http://www.microsoft.com/japan/msdn/net/bb308959.aspx
Part4 LINQで変わるデータベース開発:ITpro
http://itpro.nikkeibp.co.jp/article/COLUMN/20080116/291140/?P=1&ST=develop
スレ立てるの早すぎだと思われ
然程使ってもいないのに意見の交換なんて出来ませぬ
http://www.microsoft.com/japan/msdn/net/bb308959.aspx
Part4 LINQで変わるデータベース開発:ITpro
http://itpro.nikkeibp.co.jp/article/COLUMN/20080116/291140/?P=1&ST=develop
スレ立てるの早すぎだと思われ
然程使ってもいないのに意見の交換なんて出来ませぬ
2008/02/11(月) 18:16:46
>>1-17
1行に詰め込まないでインデントしようよ。
1行に詰め込まないでインデントしようよ。
2008/02/11(月) 18:58:15
最後の一つだけインデント入れてみた
private void Test8() {
using (var myDataAdapter = new System.Data.SqlClient.SqlDataAdapter(
"select * from Production.Location",
"Data Source=貴方のPC;Initial Catalog=AdventureWorks;Integrated Security=True"
)
) {
// サンプルデータベースからデータを取り込む
var dataTable1 = new System.Data.DataTable();
myDataAdapter.Fill(dataTable1);
// LocationIDが10以下の行のみのテーブルを作る
var srcTable = dataTable1.AsEnumerable() ;
var dstTable =
from row in srcTable
where row.Field<short>("LocationID") < 10
select row;
// ためしに表示
dataGridView1.DataSource = dataTable1;
dataGridView2.DataSource = dstTable.CopyToDataTable();
}
}
private void Test8() {
using (var myDataAdapter = new System.Data.SqlClient.SqlDataAdapter(
"select * from Production.Location",
"Data Source=貴方のPC;Initial Catalog=AdventureWorks;Integrated Security=True"
)
) {
// サンプルデータベースからデータを取り込む
var dataTable1 = new System.Data.DataTable();
myDataAdapter.Fill(dataTable1);
// LocationIDが10以下の行のみのテーブルを作る
var srcTable = dataTable1.AsEnumerable() ;
var dstTable =
from row in srcTable
where row.Field<short>("LocationID") < 10
select row;
// ためしに表示
dataGridView1.DataSource = dataTable1;
dataGridView2.DataSource = dstTable.CopyToDataTable();
}
}
2008/02/11(月) 19:11:14
どんどんコードが短くなる気持のよいビデオです
http://www.microsoft.com/uk/msdn/nuggets/nugget/227/Decomposing-LINQ.aspx
http://www.microsoft.com/uk/msdn/nuggets/nugget/227/Decomposing-LINQ.aspx
2008/02/12(火) 16:11:50
続き(>>17)
今日は System.Data.Linq.DataContext を使ったさらなる単純な例。
データベースへのアクセスの高速化もやりたいと思ったんですが、そんなの興味無い人多いと思うので、思いとどまって簡単化の方のみとします。
まずテーブルと同じ形式を持つクラスを作成します。
中身の無い { get; set; } は、event に対するdelegateのように、自動的にその型のインスタンスを生成してアクセスできるようにする物です。
C#の言語仕様書を見てください。
今日は System.Data.Linq.DataContext を使ったさらなる単純な例。
データベースへのアクセスの高速化もやりたいと思ったんですが、そんなの興味無い人多いと思うので、思いとどまって簡単化の方のみとします。
まずテーブルと同じ形式を持つクラスを作成します。
中身の無い { get; set; } は、event に対するdelegateのように、自動的にその型のインスタンスを生成してアクセスできるようにする物です。
C#の言語仕様書を見てください。
2008/02/12(火) 16:12:29
続き(>>23)
// Name の後ろにはテーブルの名前
[System.Data.Linq.Mapping.Table(Name = "Production.Location")]
public class TableLocation
{
// 重要:項目名はデータベースのコラム名とあわせておく
// ここでは、さらにプライマリキーとして認識させる
[System.Data.Linq.Mapping.Column(IsPrimaryKey = true)]
public short LocationID { get; set; }
[System.Data.Linq.Mapping.Column]
public string Name { get; set; }
[System.Data.Linq.Mapping.Column]
public System.Decimal CostRate { get; set; }
[System.Data.Linq.Mapping.Column]
public System.Decimal Availability { get; set; }
[System.Data.Linq.Mapping.Column]
public System.DateTime ModifiedDate { get; set; }
}
// Name の後ろにはテーブルの名前
[System.Data.Linq.Mapping.Table(Name = "Production.Location")]
public class TableLocation
{
// 重要:項目名はデータベースのコラム名とあわせておく
// ここでは、さらにプライマリキーとして認識させる
[System.Data.Linq.Mapping.Column(IsPrimaryKey = true)]
public short LocationID { get; set; }
[System.Data.Linq.Mapping.Column]
public string Name { get; set; }
[System.Data.Linq.Mapping.Column]
public System.Decimal CostRate { get; set; }
[System.Data.Linq.Mapping.Column]
public System.Decimal Availability { get; set; }
[System.Data.Linq.Mapping.Column]
public System.DateTime ModifiedDate { get; set; }
}
2008/02/12(火) 16:13:13
続き(>>24)
private void Test9()
{
// DataContext を使ったバージョン
using (var myDataContext = new System.Data.Linq.DataContext("Data Source=貴方のPC;Initial Catalog=AdventureWorks;Integrated Security=True"))
{
// サンプルデータベースからデータを取り込む
System.Data.Linq.Table<TableLocation> orginalTable = myDataContext.GetTable<TableLocation>();
// LocationIDが10以下の行のみのテーブルを作る
var lessThan10Table = from row in orginalTable where row.LocationID < 10 select row;
// ためしに表示
this.dataGridView1.DataSource = orginalTable;
this.dataGridView2.DataSource = lessThan10Table;
// *** 重要な特徴の紹介 ***
// キャストしなくても使えるのでミスが少なく便利である
foreach (TableLocation tmp in lessThan10Table)
{
System.Console.WriteLine("{0},{1},{2},{3},{4}"
, tmp.LocationID
, tmp.Name
, tmp.CostRate
, tmp.Availability
, tmp.ModifiedDate);
}
}
}
private void Test9()
{
// DataContext を使ったバージョン
using (var myDataContext = new System.Data.Linq.DataContext("Data Source=貴方のPC;Initial Catalog=AdventureWorks;Integrated Security=True"))
{
// サンプルデータベースからデータを取り込む
System.Data.Linq.Table<TableLocation> orginalTable = myDataContext.GetTable<TableLocation>();
// LocationIDが10以下の行のみのテーブルを作る
var lessThan10Table = from row in orginalTable where row.LocationID < 10 select row;
// ためしに表示
this.dataGridView1.DataSource = orginalTable;
this.dataGridView2.DataSource = lessThan10Table;
// *** 重要な特徴の紹介 ***
// キャストしなくても使えるのでミスが少なく便利である
foreach (TableLocation tmp in lessThan10Table)
{
System.Console.WriteLine("{0},{1},{2},{3},{4}"
, tmp.LocationID
, tmp.Name
, tmp.CostRate
, tmp.Availability
, tmp.ModifiedDate);
}
}
}
26デフォルトの名無しさん
2008/02/12(火) 16:14:20 今日はこれでおしまい
データベースを知らない人にも解りやすい、データベース不使用例もそのうち作ってみます。
データベースを知らない人にも解りやすい、データベース不使用例もそのうち作ってみます。
2008/02/12(火) 21:46:14
「プロジェクト」の「新しい項目の追加」で「LINQ to SQL クラス」のテンプレートが
追加されるけど知らない人多いよね。これで>>24のを自動生成してくれる。
追加されるけど知らない人多いよね。これで>>24のを自動生成してくれる。
28デフォルトの名無しさん
2008/02/13(水) 13:39:40 ども、>>1です、まだ始めたばかりで右も左もわかりませんがよろしくお願いします。
驚きました、プロジェクトから Linq To Sql を作成して、サーバーエクスプローラで必要なデータベースを接続したら、テーブルをドラックアンドドロップでポイだったんですね。
ちょっちょっと、これは何にもする事が無いです、いきなりこのスレ終了ですかぁ(^^;
せっかく建てたのだから何かネタ考えて続けて見ます・・・
private void Test10()
{
using (var dataContext = new TestTableDataContext())
{
var table = dataContext.GetTable<Location>();
this.dataGridView1.DataSource = table;
this.dataGridView2.DataSource = from row in table where row.LocationID < 10 select row;
}
}
驚きました、プロジェクトから Linq To Sql を作成して、サーバーエクスプローラで必要なデータベースを接続したら、テーブルをドラックアンドドロップでポイだったんですね。
ちょっちょっと、これは何にもする事が無いです、いきなりこのスレ終了ですかぁ(^^;
せっかく建てたのだから何かネタ考えて続けて見ます・・・
private void Test10()
{
using (var dataContext = new TestTableDataContext())
{
var table = dataContext.GetTable<Location>();
this.dataGridView1.DataSource = table;
this.dataGridView2.DataSource = from row in table where row.LocationID < 10 select row;
}
}
2008/02/13(水) 13:49:37
このデザイナは、細かい所まで完全に実装してくれますね
自前で動的にテーブルやDBを作成するにしても、一旦SqlSever上でダミーテーブルを作って
コードを生成しておいて、それをコピペで取ってきて変更する方が効率が良いように思えてきました。
自前で動的にテーブルやDBを作成するにしても、一旦SqlSever上でダミーテーブルを作って
コードを生成しておいて、それをコピペで取ってきて変更する方が効率が良いように思えてきました。
2008/02/13(水) 14:02:30
2008/02/13(水) 14:09:09
DB板は、あっちはアドミニの人ばかりです。
マの人がほとんど居ないから余計伸びないです。
プログラム的な事は聞いても答えが返ってくることまずないですし。
マの人がほとんど居ないから余計伸びないです。
プログラム的な事は聞いても答えが返ってくることまずないですし。
2008/02/15(金) 00:07:33
検索してからC#オブジェクトに変換する手間がとても万度くさい自分はLINQヽ(´ー`)ノマンセーです。
遅くても(・ε・)キニシナイ!!。
遅くても(・ε・)キニシナイ!!。
33デフォルトの名無しさん
2008/02/15(金) 03:30:14 IronLisp#早く作れよ
2008/02/15(金) 08:59:25
ググれカス
2008/02/15(金) 10:20:31
DBを使わなくてもLINQは便利なんだよ〜!ってことを布教するためw、
普通のコレクションに対してロジックを実行するクエリのサンプルを示してみます。
>>10が言うように、グループ化の処理をクエリ一発で書けるのは実に魅力的です。
ファイル名を格納したstring配列 files に対して処理を行います。
// 拡張子ごとにファイル名をグループ化するクエリ
var extGroupQuery = from filename in files
let ext = System.IO.Path.GetExtension(filename).ToLower()
group filename by ext into extGroup
select extGroup;
// グループ化したクエリは2重のIEnumerable<T>になってます
foreach (var extGroup in extGroupQuery)
{
Console.WriteLine("Extension: {0}, Count: {1}", extGroup.Key, extGroup.Count());
foreach (var filename in extGroup)
{
Console.WriteLine("\t{0}", filename);
}
}
普通のコレクションに対してロジックを実行するクエリのサンプルを示してみます。
>>10が言うように、グループ化の処理をクエリ一発で書けるのは実に魅力的です。
ファイル名を格納したstring配列 files に対して処理を行います。
// 拡張子ごとにファイル名をグループ化するクエリ
var extGroupQuery = from filename in files
let ext = System.IO.Path.GetExtension(filename).ToLower()
group filename by ext into extGroup
select extGroup;
// グループ化したクエリは2重のIEnumerable<T>になってます
foreach (var extGroup in extGroupQuery)
{
Console.WriteLine("Extension: {0}, Count: {1}", extGroup.Key, extGroup.Count());
foreach (var filename in extGroup)
{
Console.WriteLine("\t{0}", filename);
}
}
3635
2008/02/15(金) 10:24:47 さらに集計処理を行います
クエリの中でオブジェクトを生成し、集計処理に利用したりできます
// 拡張子ごとの合計サイズを取得する(foreachを使うとこんな感じ)
Dictionary<string, long> sizeDic = new Dictionary<string, long>();
foreach (var extGroup in extGroupQuery)
{
var sizeQuery1 = from filename in extGroup
let fileinfo = new System.IO.FileInfo(filename)
select fileinfo.Length;
long totalSize = sizeQuery1.Sum();
sizeDic[extGroup.Key] = totalSize;
}
// 拡張子ごとの合計サイズを取得する(サブクエリを使う)
// クエリ内でさらにクエリを定義できます(totalSizeQueryはsizeQuery1とまったく同じです)
var sizeQuery2 = from extGroup in extGroupQuery
let totalSizeQuery = (from filename in extGroup
let fileinfo = new System.IO.FileInfo(filename)
select fileinfo.Length)
select new { Extension = extGroup.Key, TotalSize = totalSizeQuery.Sum() };
クエリの中でオブジェクトを生成し、集計処理に利用したりできます
// 拡張子ごとの合計サイズを取得する(foreachを使うとこんな感じ)
Dictionary<string, long> sizeDic = new Dictionary<string, long>();
foreach (var extGroup in extGroupQuery)
{
var sizeQuery1 = from filename in extGroup
let fileinfo = new System.IO.FileInfo(filename)
select fileinfo.Length;
long totalSize = sizeQuery1.Sum();
sizeDic[extGroup.Key] = totalSize;
}
// 拡張子ごとの合計サイズを取得する(サブクエリを使う)
// クエリ内でさらにクエリを定義できます(totalSizeQueryはsizeQuery1とまったく同じです)
var sizeQuery2 = from extGroup in extGroupQuery
let totalSizeQuery = (from filename in extGroup
let fileinfo = new System.IO.FileInfo(filename)
select fileinfo.Length)
select new { Extension = extGroup.Key, TotalSize = totalSizeQuery.Sum() };
3735
2008/02/15(金) 10:26:11 // .Sum()の場所を変えてみる(結果はsizeQuery2と同じです)
var sizeQuery3 = from extGroup in extGroupQuery
let totalSize = (from filename in extGroup
let fileinfo = new System.IO.FileInfo(filename)
select fileinfo.Length).Sum()
select new { Extension = extGroup.Key, TotalSize = totalSize };
// サブクエリを拡張メソッドに変えてみる(場合によってはサブクエリよりもすっきり書けます)
var sizeQuery4 = from extGroup in extGroupQuery
let totalSize = extGroup.Select<string, long>(filename => new System.IO.FileInfo(filename).Length).Sum()
select new { Extension = extGroup.Key, TotalSize = totalSize };
// extGroupQuery, sizeQuery2をまとめてみる
var sizeQuery5 = from filename in files
let ext = System.IO.Path.GetExtension(filename).ToLower()
group filename by ext into extGroup
let totalSizeQuery = (from filename in extGroup
let fileinfo = new System.IO.FileInfo(filename)
select fileinfo.Length)
select new { Extension = extGroup.Key, TotalSize = totalSizeQuery };
とりあえず以上です。
もっと気の利いた例を作ったら、また書き込みます。
var sizeQuery3 = from extGroup in extGroupQuery
let totalSize = (from filename in extGroup
let fileinfo = new System.IO.FileInfo(filename)
select fileinfo.Length).Sum()
select new { Extension = extGroup.Key, TotalSize = totalSize };
// サブクエリを拡張メソッドに変えてみる(場合によってはサブクエリよりもすっきり書けます)
var sizeQuery4 = from extGroup in extGroupQuery
let totalSize = extGroup.Select<string, long>(filename => new System.IO.FileInfo(filename).Length).Sum()
select new { Extension = extGroup.Key, TotalSize = totalSize };
// extGroupQuery, sizeQuery2をまとめてみる
var sizeQuery5 = from filename in files
let ext = System.IO.Path.GetExtension(filename).ToLower()
group filename by ext into extGroup
let totalSizeQuery = (from filename in extGroup
let fileinfo = new System.IO.FileInfo(filename)
select fileinfo.Length)
select new { Extension = extGroup.Key, TotalSize = totalSizeQuery };
とりあえず以上です。
もっと気の利いた例を作ったら、また書き込みます。
3835
2008/02/15(金) 11:52:15 >>35-37の応用で、ファイルの重複を検出するコードをLINQでコンパクトに書いてみます。
次のメソッドが存在するという前提です。
static string GetMD5String(string filename)
{
using (System.Security.Cryptography.MD5CryptoServiceProvider md5
= new System.Security.Cryptography.MD5CryptoServiceProvider())
{
byte[] data = System.IO.File.ReadAllBytes(filename);
byte[] hash = md5.ComputeHash(data);
StringBuilder buf = new StringBuilder();
foreach (byte b in hash)
{
buf.AppendFormat("{0:x2}", b);
}
return buf.ToString();
}
}
次のメソッドが存在するという前提です。
static string GetMD5String(string filename)
{
using (System.Security.Cryptography.MD5CryptoServiceProvider md5
= new System.Security.Cryptography.MD5CryptoServiceProvider())
{
byte[] data = System.IO.File.ReadAllBytes(filename);
byte[] hash = md5.ComputeHash(data);
StringBuilder buf = new StringBuilder();
foreach (byte b in hash)
{
buf.AppendFormat("{0:x2}", b);
}
return buf.ToString();
}
}
3935
2008/02/15(金) 11:52:51 まずは単純だけど遅いバージョンから
// ファイルをハッシュ値でグループ化する
// 全ファイルを読み込んでハッシュ値を計算するので遅いです
var hashGroupQuery = from filehash in
(from filename in files
let hash = GetMD5String(filename)
select new { Filename = filename, Hash = hash })
group filehash by filehash.Hash into hashGroup
where hashGroup.Count() >= 2
select hashGroup;
foreach (var hashGroup in hashGroupQuery)
{
Console.WriteLine("Hash: {0}, Count: {1}", hashGroup.Key, hashGroup.Count());
foreach (var filehash in hashGroup)
{
Console.WriteLine("\t{0}", filehash.Filename);
}
}
// ファイルをハッシュ値でグループ化する
// 全ファイルを読み込んでハッシュ値を計算するので遅いです
var hashGroupQuery = from filehash in
(from filename in files
let hash = GetMD5String(filename)
select new { Filename = filename, Hash = hash })
group filehash by filehash.Hash into hashGroup
where hashGroup.Count() >= 2
select hashGroup;
foreach (var hashGroup in hashGroupQuery)
{
Console.WriteLine("Hash: {0}, Count: {1}", hashGroup.Key, hashGroup.Count());
foreach (var filehash in hashGroup)
{
Console.WriteLine("\t{0}", filehash.Filename);
}
}
4035
2008/02/15(金) 11:56:08 次に前処理を行って高速化したバージョン
// 処理を高速化するため、ファイルサイズでグループ化しておく
// (ファイルサイズはファイルを読み込まなくても取得できるので)
var sizeGroupQuery = from filesize in
(from filename in files
let fileinfo = new System.IO.FileInfo(filename)
let size = fileinfo.Length
select new { Filename = filename, Size = size })
group filesize by filesize.Size into sizeGroup
where sizeGroup.Count() >= 2
select sizeGroup;
foreach (var sizeGroup in sizeGroupQuery)
{
// ハッシュ値でグループ化する
var hashGroupQuery2 = from filehash in
(from filesize in sizeGroup
let hash = GetMD5String(filesize.Filename)
select new { Filename = filesize.Filename, Hash = hash })
group filehash by filehash.Hash into hashGroup
where hashGroup.Count() >= 2
select hashGroup;
foreach (var hashGroup in hashGroupQuery2)
{
// (行数オーバーのため略 >>39と同じです)
}
}
// 処理を高速化するため、ファイルサイズでグループ化しておく
// (ファイルサイズはファイルを読み込まなくても取得できるので)
var sizeGroupQuery = from filesize in
(from filename in files
let fileinfo = new System.IO.FileInfo(filename)
let size = fileinfo.Length
select new { Filename = filename, Size = size })
group filesize by filesize.Size into sizeGroup
where sizeGroup.Count() >= 2
select sizeGroup;
foreach (var sizeGroup in sizeGroupQuery)
{
// ハッシュ値でグループ化する
var hashGroupQuery2 = from filehash in
(from filesize in sizeGroup
let hash = GetMD5String(filesize.Filename)
select new { Filename = filesize.Filename, Hash = hash })
group filehash by filehash.Hash into hashGroup
where hashGroup.Count() >= 2
select hashGroup;
foreach (var hashGroup in hashGroupQuery2)
{
// (行数オーバーのため略 >>39と同じです)
}
}
41デフォルトの名無しさん
2008/02/16(土) 00:03:522008/02/16(土) 00:04:35
Q.データを確認したい
ツールバーにある DataGridView は、とりあえずデータの中身を見てみたい時にとても便利です。
DataSource プロパティーにデータをセットする事で見ることができます。
ただし、ここに設定できるオブジェクトは IList , IListSource , IBindingList , IBindingListView
の四つです。
また、要素は、フィールドメンバでは駄目で、プロパティーでなければなりません。
C# 3.0 より追加された省略形が便利です。
class Row {
public int Data1 { set ; get ; }
public int Data2 { set ; get ; }
}
dataGridView1.DataSource = new Row[] { new Row() { Data1 = 1, Data2 = 2 } };
ツールバーにある DataGridView は、とりあえずデータの中身を見てみたい時にとても便利です。
DataSource プロパティーにデータをセットする事で見ることができます。
ただし、ここに設定できるオブジェクトは IList , IListSource , IBindingList , IBindingListView
の四つです。
また、要素は、フィールドメンバでは駄目で、プロパティーでなければなりません。
C# 3.0 より追加された省略形が便利です。
class Row {
public int Data1 { set ; get ; }
public int Data2 { set ; get ; }
}
dataGridView1.DataSource = new Row[] { new Row() { Data1 = 1, Data2 = 2 } };
2008/02/16(土) 00:05:16
Q.from ... として作ったデータが見れない
IList 等に変換してしまうのが便利です。
var tableX = new [] {
new { X=1 , P=0.25 },
new { X=2 , P=0.50 },
new { X=3 , P=0.25 },
};
var table2 = from row in tableX orderby row.P select row;
dataGridView1.DataSource = table2.ToArray();
IList 等に変換してしまうのが便利です。
var tableX = new [] {
new { X=1 , P=0.25 },
new { X=2 , P=0.50 },
new { X=3 , P=0.25 },
};
var table2 = from row in tableX orderby row.P select row;
dataGridView1.DataSource = table2.ToArray();
2008/02/16(土) 00:05:53
Q.表の中から必要な要素を選択したい
where句を使います。
class Row {
public int X { set ; get ; }
public double P { set ; get ; }
}
var tableX = new Row[] {
new Row() { X=1 , P=0.25 },
new Row() { X=2 , P=0.50 },
new Row() { X=3 , P=0.25 },
};
// Xが2以下の行を選択する
var table1 = from row in tableX where row.X <= 2 select row;
// Xが2以下の行を選択したのち、さらに P <= 0.25 となる行を絞り込む
var table2 = from row in tableX where row.X <= 2 where row.P <= 0.25 select row;
dataGridView1.DataSource = table1.ToArray();
dataGridView2.DataSource = table2.ToArray();
where句を使います。
class Row {
public int X { set ; get ; }
public double P { set ; get ; }
}
var tableX = new Row[] {
new Row() { X=1 , P=0.25 },
new Row() { X=2 , P=0.50 },
new Row() { X=3 , P=0.25 },
};
// Xが2以下の行を選択する
var table1 = from row in tableX where row.X <= 2 select row;
// Xが2以下の行を選択したのち、さらに P <= 0.25 となる行を絞り込む
var table2 = from row in tableX where row.X <= 2 where row.P <= 0.25 select row;
dataGridView1.DataSource = table1.ToArray();
dataGridView2.DataSource = table2.ToArray();
2008/02/16(土) 00:06:24
Q.表をソートしたい
1.orderby句を使います、単純なソートは以下の通りです。
class Row {
public string S { set; get; }
public int D { set; get; }
}
var tableOrg = new Row[] {
new Row() { D=3 },
new Row() { D=1 },
new Row() { D=4 },
new Row() { D=1 },
new Row() { D=5 },
new Row() { D=9 },
};
// 昇順(ascending省略可)
var table1 = from row in tableOrg orderby row.D ascending select row;
// 降順
var table2 = from row in tableOrg orderby row.D descending select row;
dataGridView1.DataSource = table1.ToArray();
dataGridView2.DataSource = table2.ToArray();
1.orderby句を使います、単純なソートは以下の通りです。
class Row {
public string S { set; get; }
public int D { set; get; }
}
var tableOrg = new Row[] {
new Row() { D=3 },
new Row() { D=1 },
new Row() { D=4 },
new Row() { D=1 },
new Row() { D=5 },
new Row() { D=9 },
};
// 昇順(ascending省略可)
var table1 = from row in tableOrg orderby row.D ascending select row;
// 降順
var table2 = from row in tableOrg orderby row.D descending select row;
dataGridView1.DataSource = table1.ToArray();
dataGridView2.DataSource = table2.ToArray();
2008/02/16(土) 00:15:04
2.二つ以上の項目についてソートする場合は以下の通りです。
class Row {
public string S { set; get; }
public int D { set; get; }
}
var tableOrg = new Row[] {
new Row() { S="A" , D=3 },
new Row() { S="B" , D=1 },
new Row() { S="A" , D=4 },
new Row() { S="B" , D=1 },
new Row() { S="A" , D=5 },
new Row() { S="B" , D=9 },
};
// SとD を使って比較します
var table1 = from row in tableOrg orderby row.S, row.D select row;
dataGridView1.DataSource = table1.ToArray();
class Row {
public string S { set; get; }
public int D { set; get; }
}
var tableOrg = new Row[] {
new Row() { S="A" , D=3 },
new Row() { S="B" , D=1 },
new Row() { S="A" , D=4 },
new Row() { S="B" , D=1 },
new Row() { S="A" , D=5 },
new Row() { S="B" , D=9 },
};
// SとD を使って比較します
var table1 = from row in tableOrg orderby row.S, row.D select row;
dataGridView1.DataSource = table1.ToArray();
2008/02/16(土) 00:15:29
3.二回に分けてソートする場合は以下の通りです。(2と結果が異なります)
class Row {
public string S { set; get; }
public int D { set; get; }
}
var tableOrg = new Row[] {
new Row() { S="A" , D=3 },
new Row() { S="B" , D=1 },
new Row() { S="A" , D=4 },
new Row() { S="B" , D=1 },
new Row() { S="A" , D=5 },
new Row() { S="B" , D=9 },
};
// SとD を使って比較します
var table1 = from row in tableOrg orderby row.S orderby row.D select row;
dataGridView1.DataSource = table1.ToArray();
class Row {
public string S { set; get; }
public int D { set; get; }
}
var tableOrg = new Row[] {
new Row() { S="A" , D=3 },
new Row() { S="B" , D=1 },
new Row() { S="A" , D=4 },
new Row() { S="B" , D=1 },
new Row() { S="A" , D=5 },
new Row() { S="B" , D=9 },
};
// SとD を使って比較します
var table1 = from row in tableOrg orderby row.S orderby row.D select row;
dataGridView1.DataSource = table1.ToArray();
2008/02/16(土) 09:02:20
ところで、LINQってどう発音するの?
2008/02/16(土) 09:48:38
発音は link と同じらしいよ。
2008/02/16(土) 17:51:35
>>1 です、今日は、表の結合のやり方を紹介します。
2008/02/16(土) 17:52:36
Q.表を結合したい1(クロス結合)
Row1の表にRow2の表の要素をすべて結合します。
class Row1 { public string S { set; get; } }
class Row2 { public string S { set; get; } }
class Row3 { public string R1 { set; get; } public string R2 { set; get; } }
var tableOrg1 = new Row1[] { new Row1() { S="赤" }, new Row1() { S="青" },};
var tableOrg2 = new Row2[] { new Row2() { S="青" }, new Row2() { S="緑" },};
var table1 = from row1 in tableOrg1 from row2 in tableOrg2 select new Row3() { R1 = row1.S, R2 = row2.S };
dataGridView1.DataSource = table1.ToArray();
dataGridView2.DataSource = table2.ToArray();
table1 の結果
赤 青
赤 緑
青 青
青 緑
この機能、一見は使い道がなさそうですが、これをフィルターしてゆく事により価値が出てきます。
Row1の表にRow2の表の要素をすべて結合します。
class Row1 { public string S { set; get; } }
class Row2 { public string S { set; get; } }
class Row3 { public string R1 { set; get; } public string R2 { set; get; } }
var tableOrg1 = new Row1[] { new Row1() { S="赤" }, new Row1() { S="青" },};
var tableOrg2 = new Row2[] { new Row2() { S="青" }, new Row2() { S="緑" },};
var table1 = from row1 in tableOrg1 from row2 in tableOrg2 select new Row3() { R1 = row1.S, R2 = row2.S };
dataGridView1.DataSource = table1.ToArray();
dataGridView2.DataSource = table2.ToArray();
table1 の結果
赤 青
赤 緑
青 青
青 緑
この機能、一見は使い道がなさそうですが、これをフィルターしてゆく事により価値が出てきます。
2008/02/16(土) 17:53:19
Q.表を結合したい2(等価結合、きっと良く使うに違いない)
Row1の表にRow2の表の要素を普通に結合します。
この例では、 tableOrg1 の Index 番号と同じ Index のある tableOrg2 の列に結合します。
class Row1 { public int LineNo { set; get; } public int Index { set; get; } }
class Row2 { public int Index { set; get; } public string Data1 { set; get; } public string Data2 { set; get; } }
class Row3 { public int LineNo { set; get; } public string Data1 { set; get; } public string Data2 { set; get; } }
var tableOrg1 = new Row1[] {
new Row1() { LineNo=1 , Index = 3 },
new Row1() { LineNo=2 , Index = 1 },
new Row1() { LineNo=3 , Index = 4 },
new Row1() { LineNo=4 , Index = 1 },
new Row1() { LineNo=5 , Index = 5 },
};
var tableOrg2 = new Row2[] {
new Row2() { Index=1 , Data1 = "Index1" , Data2="ABC" },
new Row2() { Index=2 , Data1 = "Index2" , Data2="DEF" },
new Row2() { Index=3 , Data1 = "Index3" , Data2="GHI" },
new Row2() { Index=4 , Data1 = "Index4" , Data2="JKL" },
new Row2() { Index=5 , Data1 = "Index5" , Data2="MNL" },
};
var table1 = from row1 in tableOrg1 join row2 in tableOrg2 on row1.Index equals row2.Index select new Row3() { LineNo = row1.LineNo, Data1 = row2.Data1, Data2 = row2.Data2 };
table1 の結果
1 Index3 GHI
2 Index1 ABC
3 Index4 JKL
4 Index1 ABC
5 Index5 MNL
Row1の表にRow2の表の要素を普通に結合します。
この例では、 tableOrg1 の Index 番号と同じ Index のある tableOrg2 の列に結合します。
class Row1 { public int LineNo { set; get; } public int Index { set; get; } }
class Row2 { public int Index { set; get; } public string Data1 { set; get; } public string Data2 { set; get; } }
class Row3 { public int LineNo { set; get; } public string Data1 { set; get; } public string Data2 { set; get; } }
var tableOrg1 = new Row1[] {
new Row1() { LineNo=1 , Index = 3 },
new Row1() { LineNo=2 , Index = 1 },
new Row1() { LineNo=3 , Index = 4 },
new Row1() { LineNo=4 , Index = 1 },
new Row1() { LineNo=5 , Index = 5 },
};
var tableOrg2 = new Row2[] {
new Row2() { Index=1 , Data1 = "Index1" , Data2="ABC" },
new Row2() { Index=2 , Data1 = "Index2" , Data2="DEF" },
new Row2() { Index=3 , Data1 = "Index3" , Data2="GHI" },
new Row2() { Index=4 , Data1 = "Index4" , Data2="JKL" },
new Row2() { Index=5 , Data1 = "Index5" , Data2="MNL" },
};
var table1 = from row1 in tableOrg1 join row2 in tableOrg2 on row1.Index equals row2.Index select new Row3() { LineNo = row1.LineNo, Data1 = row2.Data1, Data2 = row2.Data2 };
table1 の結果
1 Index3 GHI
2 Index1 ABC
3 Index4 JKL
4 Index1 ABC
5 Index5 MNL
2008/02/16(土) 17:54:00
Q.表を結合したい3(非等価結合、やや使う違いない)
let を使って、選択した行を保持する事により実現できます。
class 得点表 { public string 氏名 { set; get; } public int 得点 { set; get; } }
class 評価表 { public int 以上 { set; get; } public int 未満 { set; get; } public string 評価 { set; get; } }
class 氏名と評価 { public string 氏名 { set; get; } public string 評価 { set; get; } }
var tableOrg1 = new 得点表[] {
new 得点表() { 氏名="Aさん" , 得点=10 },
new 得点表() { 氏名="Bさん" , 得点=100 },
new 得点表() { 氏名="Cさん" , 得点=60 },
};
var tableOrg2 = new 評価表[] {
new 評価表() { 以上=0 , 未満=20, 評価="丙" },
new 評価表() { 以上=20 , 未満=70, 評価="乙" },
new 評価表() { 以上=70 , 未満=101, 評価="甲" },
};
var table1 = from row1 in tableOrg1
let selectLines = from row2 in tableOrg2 where (row2.以上 <= row1.得点 && row1.得点 < row2.未満) select row2
select new 氏名と評価() { 氏名 = row1.氏名, 評価 = selectLines.First().評価 };
table1 の結果
Aさん 丙
Bさん 甲
Cさん 乙
あんま綺麗じゃない……equalsに対してLINQの拡張求む > Microsoft
let を使って、選択した行を保持する事により実現できます。
class 得点表 { public string 氏名 { set; get; } public int 得点 { set; get; } }
class 評価表 { public int 以上 { set; get; } public int 未満 { set; get; } public string 評価 { set; get; } }
class 氏名と評価 { public string 氏名 { set; get; } public string 評価 { set; get; } }
var tableOrg1 = new 得点表[] {
new 得点表() { 氏名="Aさん" , 得点=10 },
new 得点表() { 氏名="Bさん" , 得点=100 },
new 得点表() { 氏名="Cさん" , 得点=60 },
};
var tableOrg2 = new 評価表[] {
new 評価表() { 以上=0 , 未満=20, 評価="丙" },
new 評価表() { 以上=20 , 未満=70, 評価="乙" },
new 評価表() { 以上=70 , 未満=101, 評価="甲" },
};
var table1 = from row1 in tableOrg1
let selectLines = from row2 in tableOrg2 where (row2.以上 <= row1.得点 && row1.得点 < row2.未満) select row2
select new 氏名と評価() { 氏名 = row1.氏名, 評価 = selectLines.First().評価 };
table1 の結果
Aさん 丙
Bさん 甲
Cさん 乙
あんま綺麗じゃない……equalsに対してLINQの拡張求む > Microsoft
54デフォルトの名無しさん
2008/02/16(土) 17:54:50 そのうち、逆引きLINQでも作って、纏めてみたいな……
こうやって、Q&A を作ってみると、LINQは集合の積的な演算は強いのに和の方は至って貧弱なんですね。
全部LINQにしなくても適当にメソッドを使えば良いという話もありますが……
こうやって、Q&A を作ってみると、LINQは集合の積的な演算は強いのに和の方は至って貧弱なんですね。
全部LINQにしなくても適当にメソッドを使えば良いという話もありますが……
2008/02/16(土) 18:39:49
>>54
まあ、リレーショナルデータベースがそういうものだからね<テーブル積を多用
まあ、リレーショナルデータベースがそういうものだからね<テーブル積を多用
2008/02/16(土) 18:59:05
2008/02/16(土) 19:11:27
そういう概念を導入すると、
作り手だけでなくて、使い手にも圏論の知識を強要することにならないかな。
LINQ は、リレーショナルデータベースの文化を
OOP 言語に導入したものだから、
少なくとも SQL チックに select とか where ってキーワードを使ってる限り、
リレーショナルデータベースの文化を大きく逸脱するようなことは
しない方がいいと思う。
ヘジたんがクエリ式否定派(関数形式ばっかり使う)な理由も
そういうところにあるのかもね。
作り手だけでなくて、使い手にも圏論の知識を強要することにならないかな。
LINQ は、リレーショナルデータベースの文化を
OOP 言語に導入したものだから、
少なくとも SQL チックに select とか where ってキーワードを使ってる限り、
リレーショナルデータベースの文化を大きく逸脱するようなことは
しない方がいいと思う。
ヘジたんがクエリ式否定派(関数形式ばっかり使う)な理由も
そういうところにあるのかもね。
2008/02/16(土) 19:11:51
>>53
ちょっとだけ短くしたよ。
var table1 = from row1 in tableOrg1
let 評価 = tableOrg2.First(row2 => row2.以上 <= row1.得点 && row1.得点 < row2.未満)
select new { row1.氏名, 評価.評価 };
ちょっとだけ短くしたよ。
var table1 = from row1 in tableOrg1
let 評価 = tableOrg2.First(row2 => row2.以上 <= row1.得点 && row1.得点 < row2.未満)
select new { row1.氏名, 評価.評価 };
2008/02/16(土) 19:15:04
あと、同値分類みたいなのは、group by じゃだめ?
6058
2008/02/16(土) 19:24:17 >>53
パターンマッチっぽくしてみたよ。
var table1 =
from row1 in tableOrg1
let 評価結果 = tableOrg2.Where(row2 => row2.以上 <= row1.得点 && row1.得点 < row2.未満)
.Select(row2 => row2.評価)
.Concat(Enumerable.Repeat("見つからないよ", 1))
.Take(1)
from 評価 in 評価結果
select new { row1.氏名, 評価 };
パターンマッチっぽくしてみたよ。
var table1 =
from row1 in tableOrg1
let 評価結果 = tableOrg2.Where(row2 => row2.以上 <= row1.得点 && row1.得点 < row2.未満)
.Select(row2 => row2.評価)
.Concat(Enumerable.Repeat("見つからないよ", 1))
.Take(1)
from 評価 in 評価結果
select new { row1.氏名, 評価 };
2008/02/16(土) 20:13:38
>>1です
>>57
概念を導入することと、どう表現してどう使わせるかは違うと思うんですよ
高度な概念も、図にしてみれば、あんたバカ、何当り前の事をと思わずにはいられない概念は多いと思うんですよ。
圏論のそんな物の内の一つだと思っています。
ちなみにヘジたん理論無視の直感実装大好きです、実装は理屈じゃないですよ、いいと思ったらそれがいいんだと思ってます。
理屈は後付け、原爆の爆縮レンズが開発される時に、火薬職人が二種類の火薬使えばいいじゃんといって、頭でっかちのノイマンが計算するっていうのは悪くないと
ここでは、火薬職人がヘジたんで、頭でっかちがリサーチの人たちですね。
>>60
ありがとさんです、なるほどなるほど、いろいろ参考になりますです。
まだまだ初心者なんで今後ともよろしくお願いします。
>>57
概念を導入することと、どう表現してどう使わせるかは違うと思うんですよ
高度な概念も、図にしてみれば、あんたバカ、何当り前の事をと思わずにはいられない概念は多いと思うんですよ。
圏論のそんな物の内の一つだと思っています。
ちなみにヘジたん理論無視の直感実装大好きです、実装は理屈じゃないですよ、いいと思ったらそれがいいんだと思ってます。
理屈は後付け、原爆の爆縮レンズが開発される時に、火薬職人が二種類の火薬使えばいいじゃんといって、頭でっかちのノイマンが計算するっていうのは悪くないと
ここでは、火薬職人がヘジたんで、頭でっかちがリサーチの人たちですね。
>>60
ありがとさんです、なるほどなるほど、いろいろ参考になりますです。
まだまだ初心者なんで今後ともよろしくお願いします。
2008/02/16(土) 20:26:54
高度な概念といえば、たとえばλ式なんかがそうなんですが、関数だと思うと恐ろしい事になりますが、
あれってとどのつまりは、引数が添え字になっている唯のベクトルですよね。なにやら要素が並んでいるだけの物です。
よく無限次元になってしまうので、普通に書けないからああ書いたというだけで……
もっと解り易くならないかなと思ったりします。
あれってとどのつまりは、引数が添え字になっている唯のベクトルですよね。なにやら要素が並んでいるだけの物です。
よく無限次元になってしまうので、普通に書けないからああ書いたというだけで……
もっと解り易くならないかなと思ったりします。
2008/02/16(土) 21:07:54
DB屋もやってる俺からみると、これはぶっちゃけキモい
変にSQLの知識あるとちょっと慣れそうにないなぁ、これは
変にSQLの知識あるとちょっと慣れそうにないなぁ、これは
2008/02/17(日) 00:29:39
>>63
俺も一応オラクルマスター持ちなんだが(システム屋から足を洗って長いけど)、
それはそれ、これはこれだな。
DBとだけ使っている限りは、SQL以上のことができるわけじゃないから「ただのキモいSQL」という見方も、そう間違ってはいないだろう。
SQLを基準にして見れば、SQLとの違いが気持ち悪いのは確か。しかし、メモリ上のデータのグループ化やら結合やら、定型的なわりに再利用しづらいコードを
いちいち書いては「こんな処理、SQLならSELECT文一発なのに」と思っていた人にとっては、むしろSQLに近づいた感じなのではないだろうか。
俺も一応オラクルマスター持ちなんだが(システム屋から足を洗って長いけど)、
それはそれ、これはこれだな。
DBとだけ使っている限りは、SQL以上のことができるわけじゃないから「ただのキモいSQL」という見方も、そう間違ってはいないだろう。
SQLを基準にして見れば、SQLとの違いが気持ち悪いのは確か。しかし、メモリ上のデータのグループ化やら結合やら、定型的なわりに再利用しづらいコードを
いちいち書いては「こんな処理、SQLならSELECT文一発なのに」と思っていた人にとっては、むしろSQLに近づいた感じなのではないだろうか。
2008/02/17(日) 00:53:13
OOP 言語が SQL に近づいたこと
(より「意図通りに書ける」ようになった)も重要だし、
in-memory オブジェクト、XML、DB に対して
ほぼ同じ書式でクエリが書けることも重要かと。
(より「意図通りに書ける」ようになった)も重要だし、
in-memory オブジェクト、XML、DB に対して
ほぼ同じ書式でクエリが書けることも重要かと。
2008/02/17(日) 20:41:50
LINQとSQLの違いのひとつにプランナの有無がある。
LINQは処理順に書かなくてはならないし、必ず記述順で処理される。
LINQはSQLの類似品と考えるより、
Enumeratorやコールバック(ラムダ)を使ったパイプライン処理であり
コレクション処理の延長だと思ったほうが誤解がない。
LINQは処理順に書かなくてはならないし、必ず記述順で処理される。
LINQはSQLの類似品と考えるより、
Enumeratorやコールバック(ラムダ)を使ったパイプライン処理であり
コレクション処理の延長だと思ったほうが誤解がない。
2008/02/17(日) 21:31:55
2008/02/17(日) 21:32:46
Q.表を分割したい
LINQの文法は、例えば以下のような形式になっています。
from アイテム名 in 元データ where アイテム名.項目=="条件のあっているデータ" select 新しい行の定義
上記の文の最後の部分「select 新しい行の定義」の部分を「group 新しい行の定義 by ふるい分けの基準となる値」
とする事により表を分割できます。
ここでは
1 "ABC"
2 "DEF"
3 "ABC"
4 "DEF"
5 "GHI"
となっている表を、以下の三つの表に分割する方法です。
ABC のある列
1 ABC
3 ABC
DEF のある列
2 DEF
4 DEF
GHI のある列
5 GHI
LINQの文法は、例えば以下のような形式になっています。
from アイテム名 in 元データ where アイテム名.項目=="条件のあっているデータ" select 新しい行の定義
上記の文の最後の部分「select 新しい行の定義」の部分を「group 新しい行の定義 by ふるい分けの基準となる値」
とする事により表を分割できます。
ここでは
1 "ABC"
2 "DEF"
3 "ABC"
4 "DEF"
5 "GHI"
となっている表を、以下の三つの表に分割する方法です。
ABC のある列
1 ABC
3 ABC
DEF のある列
2 DEF
4 DEF
GHI のある列
5 GHI
2008/02/17(日) 21:33:19
ツールボックスから DataGridView と TextBox を三つ貼り付けて以下のコードを実行すると三つの表が完成します。
var tableOrg1 = new[] {
new { LineNo = 1 , Data = "ABC" } ,
new { LineNo = 2 , Data = "DEF" } ,
new { LineNo = 3 , Data = "ABC" } ,
new { LineNo = 4 , Data = "DEF" } ,
new { LineNo = 5 , Data = "GHI" } ,
};
var dataGridViewArray = new[] { dataGridView1, dataGridView2, dataGridView3 };
var textBoxArray = new[] { textBox1, textBox2, textBox3 };
var tableArray = (from row in tableOrg1 group row by row.Data).ToArray();
for (int i = 0; i < dataGridViewArray.GetLength(0) && i < tableArray.GetLength(0); ++i) {
dataGridViewArray[i].DataSource = tableArray[i].ToArray();
textBoxArray[i].Text = tableArray[i].Key.ToString();
}
by row.Data の部分を変更することにより、例えばby row.Data.Length などとする事により複雑なふるい分けが可能です。
var tableOrg1 = new[] {
new { LineNo = 1 , Data = "ABC" } ,
new { LineNo = 2 , Data = "DEF" } ,
new { LineNo = 3 , Data = "ABC" } ,
new { LineNo = 4 , Data = "DEF" } ,
new { LineNo = 5 , Data = "GHI" } ,
};
var dataGridViewArray = new[] { dataGridView1, dataGridView2, dataGridView3 };
var textBoxArray = new[] { textBox1, textBox2, textBox3 };
var tableArray = (from row in tableOrg1 group row by row.Data).ToArray();
for (int i = 0; i < dataGridViewArray.GetLength(0) && i < tableArray.GetLength(0); ++i) {
dataGridViewArray[i].DataSource = tableArray[i].ToArray();
textBoxArray[i].Text = tableArray[i].Key.ToString();
}
by row.Data の部分を変更することにより、例えばby row.Data.Length などとする事により複雑なふるい分けが可能です。
2008/02/17(日) 21:34:14
Q.特定項目で分類したい
項目に大小比較ができれば、ソートしてしまえば良いのですが、それが無い場合には少し困った事になります。
ここでは、前出の「表を分割したい」と組み合わせた方法を紹介します。
それは、前出のLINQ文「from row in tableOrg1 group row by row.Data」の後ろに「into tmp1 from tmp2 in tmp1 select tmp2」を追加して
from row in tableOrg1 group row by row.Data into tmp1 from tmp2 in tmp1 select tmp2
とすると実現できます、まじないの部類ですが・・・うまく行きます。
var tableOrg1 = new[] {
new { LineNo = 1 , Data = "ABC" } ,
new { LineNo = 2 , Data = "DEF" } ,
new { LineNo = 3 , Data = "ABC" } ,
new { LineNo = 4 , Data = "DEF" } ,
new { LineNo = 5 , Data = "GHI" } ,
};
var table1 = from row in tableOrg1 group row by row.Data into tmp1 from tmp2 in tmp1 select tmp2;
dataGridView1.DataSource = table1.ToArray();
項目に大小比較ができれば、ソートしてしまえば良いのですが、それが無い場合には少し困った事になります。
ここでは、前出の「表を分割したい」と組み合わせた方法を紹介します。
それは、前出のLINQ文「from row in tableOrg1 group row by row.Data」の後ろに「into tmp1 from tmp2 in tmp1 select tmp2」を追加して
from row in tableOrg1 group row by row.Data into tmp1 from tmp2 in tmp1 select tmp2
とすると実現できます、まじないの部類ですが・・・うまく行きます。
var tableOrg1 = new[] {
new { LineNo = 1 , Data = "ABC" } ,
new { LineNo = 2 , Data = "DEF" } ,
new { LineNo = 3 , Data = "ABC" } ,
new { LineNo = 4 , Data = "DEF" } ,
new { LineNo = 5 , Data = "GHI" } ,
};
var table1 = from row in tableOrg1 group row by row.Data into tmp1 from tmp2 in tmp1 select tmp2;
dataGridView1.DataSource = table1.ToArray();
71デフォルトの名無しさん
2008/02/17(日) 21:35:03 linq の文法 query-body ::= query-body-clause* final-query-clause query-continuation?
この query-body-clause* の部分が複数になると急に難解になりますね。
どういう時に、使うと見通しが良くなるのか、あるいはどういう時にろくな事にならないのか
パターンとアンチパターンを揃える必要がある気がします。
この query-body-clause* の部分が複数になると急に難解になりますね。
どういう時に、使うと見通しが良くなるのか、あるいはどういう時にろくな事にならないのか
パターンとアンチパターンを揃える必要がある気がします。
2008/02/17(日) 21:40:18
2008/02/18(月) 18:11:36
>>1 です、今日は、LINQ文法の詳細をやろうと思ったのですが……
一通りざらっと見てみて、LINQの文法はひょっとして質が悪いのでは?という疑惑が湧いてきました。
LINQの核心部分は、from join その他 LINQ キーワードではなく、実際の処理が記述されている System.Linq.Enumerable であるので
これが致命傷になるとは思えないのですが、簡単に使うための上っ面としては今一な気がします。
このキーワードと文法には、変な汎用性があり、相当な広範囲にわたって複雑な処理が可能ですが
それを行うなら、メソッドベースで行ったほうが良さそうな気がします。
1.方向性としては、良くある定型について、LINQ 文法を使って完結に記述。使用例一覧に纏めておき、サクッと使う。
2.例外的なクエリについては、メソッドを使い、一つ一つ区切りながらクエリを完成させる。
こういう使い方が良いのではと思い始めました。
皆さんはどんな意見をお持ちでしょうか?
一通りざらっと見てみて、LINQの文法はひょっとして質が悪いのでは?という疑惑が湧いてきました。
LINQの核心部分は、from join その他 LINQ キーワードではなく、実際の処理が記述されている System.Linq.Enumerable であるので
これが致命傷になるとは思えないのですが、簡単に使うための上っ面としては今一な気がします。
このキーワードと文法には、変な汎用性があり、相当な広範囲にわたって複雑な処理が可能ですが
それを行うなら、メソッドベースで行ったほうが良さそうな気がします。
1.方向性としては、良くある定型について、LINQ 文法を使って完結に記述。使用例一覧に纏めておき、サクッと使う。
2.例外的なクエリについては、メソッドを使い、一つ一つ区切りながらクエリを完成させる。
こういう使い方が良いのではと思い始めました。
皆さんはどんな意見をお持ちでしょうか?
74デフォルトの名無しさん
2008/02/18(月) 18:13:51 http://www.microsoft.com/japan/msdn/net/bb308959.aspx より。
今日はこれを、初心者向けの説明にしようと思ったのですが……難しすぎ
区切り無く、際限なく、限りなく書き方が広がるとマニュアル化ができません。
query-continuation? の定義に query-body があるのが最悪だ。
だれがこれを手際よく解説するアイディアお持ちで無いでしょうか?
query-body ::= query-body-clause* final-query-clause query-continuation?
query-body-clause ::= (from-clause | join-clause | let-clause | where-clause | orderby-clause)
join-clause ::= join itemName in srcExpr on keyExpr equals keyExpr (into itemName)?
let-clause ::= let itemName = selExpr
where-clause ::= where predExpr
orderby-clause ::= orderby (keyExpr (ascending | descending)?)*
final-query-clause ::= (select-clause | groupby-clause)
select-clause ::= select selExpr
groupby-clause ::= group selExpr by keyExpr
query-continuation ::= into itemName query-body
#ひょっとしてカンマ忘れてる?
#orderby-clause ::= orderby (keyExpr (ascending | descending)? ,)*
今日はこれを、初心者向けの説明にしようと思ったのですが……難しすぎ
区切り無く、際限なく、限りなく書き方が広がるとマニュアル化ができません。
query-continuation? の定義に query-body があるのが最悪だ。
だれがこれを手際よく解説するアイディアお持ちで無いでしょうか?
query-body ::= query-body-clause* final-query-clause query-continuation?
query-body-clause ::= (from-clause | join-clause | let-clause | where-clause | orderby-clause)
join-clause ::= join itemName in srcExpr on keyExpr equals keyExpr (into itemName)?
let-clause ::= let itemName = selExpr
where-clause ::= where predExpr
orderby-clause ::= orderby (keyExpr (ascending | descending)?)*
final-query-clause ::= (select-clause | groupby-clause)
select-clause ::= select selExpr
groupby-clause ::= group selExpr by keyExpr
query-continuation ::= into itemName query-body
#ひょっとしてカンマ忘れてる?
#orderby-clause ::= orderby (keyExpr (ascending | descending)? ,)*
2008/02/18(月) 18:52:44
>>73
LINQ って言葉の指す範囲は広くて、クエリ式もメソッド形式もどっちも LINQ よ。
from x in list みたいなのはクエリ式。
クエリ式でないと書きづらいのは、多重 from と join と let くらいかな。
まあ、transparent な変数が絡むとクエリ式使わないときつい。
逆に、クエリ式で書けないことも実に多い。
まあ、個人的には、
クエリ式で書けるものは全部クエリ式で、
それ以外だけメソッド形式で書いてる。
LINQ って言葉の指す範囲は広くて、クエリ式もメソッド形式もどっちも LINQ よ。
from x in list みたいなのはクエリ式。
クエリ式でないと書きづらいのは、多重 from と join と let くらいかな。
まあ、transparent な変数が絡むとクエリ式使わないときつい。
逆に、クエリ式で書けないことも実に多い。
まあ、個人的には、
クエリ式で書けるものは全部クエリ式で、
それ以外だけメソッド形式で書いてる。
2008/02/18(月) 18:56:38
2008/02/18(月) 19:00:39
対応関係としては、
from x in list where x > 0 select x;
↓
list.Where(x => x > 0); // 最後の Select はきえる
from x in list select x * x;
↓
list.Select(x => x * x);
from x in list select x * x into y where y > 5 select y;
↓
list.Select(x => x * x).Where(y => y > 5); // .Select の後ろにさらにメソッドが続く
from x in list where x > 0 select x;
↓
list.Where(x => x > 0); // 最後の Select はきえる
from x in list select x * x;
↓
list.Select(x => x * x);
from x in list select x * x into y where y > 5 select y;
↓
list.Select(x => x * x).Where(y => y > 5); // .Select の後ろにさらにメソッドが続く
2008/02/20(水) 00:08:01
2008/02/20(水) 04:36:32
Hibernate とは違うの?
2008/02/20(水) 10:09:28
2008/02/20(水) 18:48:34
2008/02/20(水) 20:25:54
>>79
簡単に言うと、O/Rマッピングは対症療法、LINQは原因療法、みたいな。
なんでこんなのが必要かってのは、
ttp://d.hatena.ne.jp/fromdusktildawn/20060216/1140064918
を読むと理解が深まるかも。
簡単に言うと、O/Rマッピングは対症療法、LINQは原因療法、みたいな。
なんでこんなのが必要かってのは、
ttp://d.hatena.ne.jp/fromdusktildawn/20060216/1140064918
を読むと理解が深まるかも。
2008/02/20(水) 21:16:01
LINQ最大の効果ポイントは、一般化と高速化にあるんじゃないかな
データベースから、XMLから、果ては適当なクラスや構造体まで統一手法で操作可能という点。
O/Rマッピングと目指すところがそもそも違うと思う
データベースから、XMLから、果ては適当なクラスや構造体まで統一手法で操作可能という点。
O/Rマッピングと目指すところがそもそも違うと思う
2008/02/20(水) 22:14:52
キャッシュポリシーは単純だけど、Linq to SQLはORM。
これだけはほかのと系統が違う。これで使うラムダ式は特殊なもの。
これだけはほかのと系統が違う。これで使うラムダ式は特殊なもの。
2008/02/20(水) 23:37:59
( ゚д゚)ノ ハイ!シツモーン!です。
次のように追加してくと実行時間がリニアに増えてくんだけど何か間違えてるんでしょうか?
プロジェクトごとあげてみました。
http://www.borujoa.org/upload/source/upload16875.zip
class Program {
static void Main(string[] args) {
var db =new TestDB(@"testDB.sdf");
db.DeleteDatabase();
db.CreateDatabase();
var count=0;
var tu=new TickUtil();
tu.WriteLine("begin--");
while(count++<5000){
var person=new Person{Name=string.Format("name-{0:8d}",count),
Age=count,Explanation=string.Format("Explain-{0}",count)};
db.Persons.InsertOnSubmit(person);
db.SubmitChanges();
if(count%100==0)
tu.WriteLine("new person-count={0}",count);
}
tu.WriteLine("end-");
}
}
次のように追加してくと実行時間がリニアに増えてくんだけど何か間違えてるんでしょうか?
プロジェクトごとあげてみました。
http://www.borujoa.org/upload/source/upload16875.zip
class Program {
static void Main(string[] args) {
var db =new TestDB(@"testDB.sdf");
db.DeleteDatabase();
db.CreateDatabase();
var count=0;
var tu=new TickUtil();
tu.WriteLine("begin--");
while(count++<5000){
var person=new Person{Name=string.Format("name-{0:8d}",count),
Age=count,Explanation=string.Format("Explain-{0}",count)};
db.Persons.InsertOnSubmit(person);
db.SubmitChanges();
if(count%100==0)
tu.WriteLine("new person-count={0}",count);
}
tu.WriteLine("end-");
}
}
■ このスレッドは過去ログ倉庫に格納されています
ニュース
- 【日本人の旅行離れ】国内旅行すら行けなくなった……オーバーツーリズムだけじゃない 旅行者減少の異常事態 [ぐれ★]
- 高市首相の答弁書に「台湾有事答えない」と明記 存立危機発言当時 ★12 [蚤の市★]
- “ひとり焼肉”でおなじみ「焼肉ライク」が閉店ラッシュ。なぜ「コスパが悪い」と言われてしまうのか [Gecko★]
- 中国の渡航自粛要請1カ月 大阪の観光バス予約ゼロ、東北にも波及 [蚤の市★]
- 女性天皇「賛成」69%、将来の皇位継承「不安」68%…読売世論調査 [蚤の市★]
- 【神戸】エレベーター「かご」なく男性医師が転落死 大手「三菱電機ビルソリューションズ」の担当者、安全装置切り放置か [ぐれ★]
- アップル、メモリ長期契約が打ち切られたため年明けから大幅な値上げになる模様。iPhone17今すぐ買い占めろ [709039863]
- 高市、メガソーラー廃止。環境破壊が社会問題化 [792147417]
- 女だが
- 🏡おい!返事しろ︎︎!知的障害者!
- ワイの趣味が"資格試験に申し込んで結局行かない"なんやがどんなイメージ?
- 農水省が立ち上げた「農業版価格ドットコム」失敗。サービス完全終了、運営会社2021年から債務超過・解散 [256556981]
