DOBON.NETプログラミング道掲示板

■ 「新規作成」から投稿できます。
■ マルチポストされた投稿を見つけたときは、その投稿に返信することによりご報告ください。その際は匿名で投稿し、マルチポストされている場所を併記してください。
■ スパム対策のため、メールアドレスの先頭に"_"という文字が付加されています。
RSS 2.0 RSS 2.0 | RSS 0.91 | 携帯電話用 | 自分専用のアイコンを使用するには | 掲示板への要望 | 管理人に連絡 | お気楽掲示板
■ 24時間以内に作成されたスレッドは New で表示されます。
■ 24時間以内に更新されたスレッドは UpDate で表示されます。

記事リスト ( )内の数字はレス数
NomalExcel Com オブジェクトの増殖(13) | NomalRichTextBoxのテキストをpictureBOXへ(12) | NomalPictureBoxの画像を連続保存(11) | NomalVB.NetでVB6.0と同じFontを指定しても同様に印刷されない(9) | Nomal作成した白黒画像をWordに貼り付けてから「図として保存」(8) | Nomal重なったPictureBox同士を透過する方法(7) | Nomalvb.netでExcelファイル操作(7) | NomalTreeViewの現在位置とDataGridViewの現在位置を合わせたい(7) | Nomalラジオボタンの一括設定(7) | NomalLabelで文字単位の背景色(7) | NomalTEXTBOXのプロパティを文字列に(7) | NomalDataAdapter.Updateで構文エラー(6) | Nomalキーボード+バーコードでキーボード入力を無効にしたい(6) | Nomaljumbo icon(256x256)が存在するか知る方法(6) | Nomal画像のスクロール(6) | Nomalタイマーの一括処理(6) | Nomal先頭に空白(スペース)があるファイルを読み込んでRichTextBoxへ書き出すとスペースが削除える(6) | NomalタッチキーボードでIMEを自動で切替えたい(6) | NomalPDFをフォーム上で表示させる方法につきまして(6) | Nomal特定のPCだけ発生する「パディングは無効なので削除できません」のエラーの原因(6) | Nomal全角シフト中にアクセスキーが効かない(5) | NomalVB.NETからcmdでpingを実行した時の結果(5) | NomalTabPageの背景色(5) | Nomalstyle.displayだと効率悪いから違うやり方をしたいです。(5) | Nomalグリッド表示レコードをJSONに変換(5) | NomalSeleniumで開いているページのTableを編集したい(5) | NomalMP4動画を再生する方法について(5) | NomalLableのカラー色を文字変数から変更したい(5) | NomalDatagridViewでファンクションキーを止めたい(5) | Nomalフォーム背景のみを半透明にしたい(5) | NomalCommandBuilderによって作られるCommandTextの内容(5) | NomalDataGridViewの特定セルにボタンを配置する方法(5) | NomalWebView2によるスクレ―ピング(4) | NomalC#でJpeg圧縮のTiffファイルを作成したい(4) | NomalDataGridViewのVirtualModeを有効した場合の実装方法(4) | Nomalテーブルを順番通りに直すプログラムを外部で読み込めるようにしたいです。(4) | Nomalソケット通信入門 ひらがな(4) | Nomal時間変数(文字列)の扱い(4) | NomalTreeViewとDataGridViewのスクロールを同期(シンクロ)させたい(4) | Nomalフォームのリサイズ時にDataGridViewが再描画されない(4) | NomalPDFをフォーム上で表示させる方法につきまして(4) | NomalアプリでHDMIへ出す解像度を変えたい(4) | Nomal画像の中心を基点に回転(4) | NomalDataGridViewの行ヘッダーに行番号を表示した時のエラー(4) | NomalASP.NET WebApi内でXmlReader.Create(url)がタイムアウトする(4) | Nomal抽象クラスで実装したクラスの情報を知る(3) | Nomal兆億万表記の文字列を数値に変換できる?(3) | NomalGetDirectoriesでルートを指定するとエラーになる(3) | NomalLinqにおける明示的型指定の方法(3) | Nomalデータベースからのテーブル名一覧の効率的な取得方法(3) | NomalC# Chart X軸上のグラフ表示(3) | NomalVB.NETでBluetoothデバイスの電池残量を取得する方法(3) | NomalWindowsフォームデザイナについて(3) | NomalDrawstringでの透過文字作成(3) | Nomalワンタイムパスワードのサイトに自動ログインしてアクセストークンを得る(3) | NomalJSONの複雑な入れ子内部の値を取りたい。(3) | Nomalシステム時計の設定(3) | NomalVisual Basicでエラーが出る(3) | Nomal継承元フォームで各フォームのボタン動作を検知したい(3) | NomalRichTextBoxへのドラッグ&ドロップしたExcelファイルの扱い(3) | Nomal表示動作が重くなる(3) | NomalLoadOptionのパラメータの意味(3) | Nomal1行で書くことできますか?(3) | NomalProcessクラスからbatファイル実行後、KILLできない(2) | Nomal画面遷移(モーダルとモードレス)(2) | Nomal2つのradの数値から1つの角度を求めるコードを改善できますか?(C++)(2) | Nomalコンソールアプリで、WebView2の利用(2) | NomalEntity Frameworkは、使えるか?(2) | NomalC#のlong型でオーバーフローになる(2) | Nomal正規表現のパターン表記方法(2) | Nomalこういた物を作れますか?(2) | Nomalvb.netでのExcelファイルそうさ(2) | Nomalファイルとして配置したマニフェストを優先したい(2) | NomalVB2022でクリスタルレポートが開けない(2) | Nomalエクセルのみ監視ができない(2) | NomalExcelの数値 -> 日付みたいな関数?(2) | NomalSpinWait()を使う理由(2) | Nomalantecedentってなんですか?(2) | NomalRGB値の所得(2) | NomalVB.net からAccessDBへの接続(2) | NomalテキストボックスのValidatingイベントよりも先に発生するボタン発生イベントは何でしょう?(2) | NomalWindowsエクスプローラからのドラッグ&ドロップ(2) | Nomalクリックイベントでexeを作成できるか(2) | Nomalc#で日付型の定義の仕方で質問があります。(2) | Nomal列車の時間ごとの位置情報を表示したいです。(2) | NomalUrlにアクセスするとダウンロードされるファイルを捕まえる(2) | Nomalタブレット等でスワイプによるスクロールを実装(2) | Nomalbitmapを複数スレッドで処理したい(2) | Nomal読み出し元フォームの位置取得方法(2) | Nomalコンストラクターに続く{}の意味(2) | Nomalvb.netで7zの圧縮・解凍をしたい。(2) | Nomalツールボックスにtableadapterが表示されない(1) | Nomalアセンブリ情報が載らない(1) | Nomal二次元マップから値の取得(1) | NomalDataGridViewのドロップダウンリストの表示と選択後の値を分けたい(1) | NomalVSTOによるエクセルアドインのインストーラーでのアップデート(1) | Nomalクリスタルレポート 明細部のサブレポート(0) | Nomalインストーラにて、ローミングフォルダにファイルを配置したい(0) | NomalChart X軸上の描画を切り替えたい(0) |



■記事リスト / ▼下のスレッド
■35088 / 親記事)  CommandBuilderによって作られるCommandTextの内容
□投稿者/ Wan 付き人(66回)-(2022/06/28(Tue) 12:10:57)
  • アイコン環境/言語:[VisualBasic2019 Windows10 Basic Framework4.7.2] 
    分類:[.NET] 

    VisualStudio2019で、データベースの使用を勉強しています。
    Accessに接続して、OleDbCommandBuilderを実行したところ、コメントのようなCommandTextを取得することができました。
    UPDATE文、DELETE文のCommandTextの中の(? = 1 AND 苗字 IS NULL)の意味を教えて頂けませんか?
    「苗字 IS NULL」は、レコードの苗字列の値がDbNullの場合はTrueを返すという事は理解していますが、「? = 1」の意味が解りません。
    
    詳しい方、宜しくお願い致します。
    
    (Accessのテーブル構成)
    インスタンス名	Access2010
    データベース名	データベース勉強用DB
    論理テーブル名	Test
    物理テーブル名	INSERT文.accdb
    
    列定義
    No	論理名	物理名	データ型	Null許容	主キー
    1	ID	ID	長整数(8,0)	No	    Yes
    2	苗字	苗字	テキスト型(10)	No	
    3	名前	名前	テキスト型(10)	No	
    4	年齢	年齢	十進数(18)	No	
    
    Dim oledb As String = "Microsoft.ACE.OLEDB.16.0;"
    Dim acfile As String = "D:\データベース勉強用DB\INSERT文.accdb"
    Dim Cn As New OleDb.OleDbConnection($"Provider={oledb} Data Source={acfile}")
    Dim Da As New OleDbDataAdapter("SELECT * FROM 既存テーブル", Cn)
    Dim Ds As New DataSet
    Da.Fill(Ds, "Test")
    Dim builder As OleDbCommandBuilder = New OleDbCommandBuilder(Da)
    Dim INS_Cmd = builder.GetInsertCommand()
    Dim UPD_Cmd = builder.GetUpdateCommand()
    Dim DEL_Cmd = builder.GetDeleteCommand
    
    以下のCommandTextが設定されます。
    'INS_ Cmd.CommandText : INSERT INTO 既存テーブル (苗字, 名前, 年齢) VALUES (?, ?, ?)
    
    'UPD_ Cmd.CommandText :UPDATE 既存テーブル SET 苗字 = ?, 名前 = ?, 年齢 = ? 
    WHERE ((ID = ?) AND 
    ((? = 1 AND 苗字 IS NULL) OR (苗字 = ?)) AND 
    ((? = 1 AND 名前 IS NULL) OR (名前 = ?)) AND 
    ((? = 1 AND 年齢 IS NULL) OR (年齢 = ?)))
    
    ' DEL_Cmd.CommandText:DELETE FROM 既存テーブル 
    WHERE ((ID = ?) AND 
    ((? = 1 AND 苗字 IS NULL) OR (苗字 = ?)) AND 
    ((? = 1 AND 名前 IS NULL) OR (名前 = ?)) AND 
    ((? = 1 AND 年齢 IS NULL) OR (年齢 = ?)))
    
    

違反を報告
引用返信

▽[全レス5件(ResNo.1-5 表示)]
■35089 / ResNo.1)  Re[1]: CommandBuilderによって作られるCommandTextの内容
□投稿者/ 魔界の仮面弁士 大御所(1430回)-(2022/06/28(Tue) 14:16:04)
  • アイコンNo35088に返信(Wanさんの記事)
    > UPDATE文、DELETE文のCommandTextの中の(? = 1 AND 苗字 IS NULL)の意味を教えて頂けませんか?

    データベース側では、名前や型を明示したパラメーターをサポートしているのですが、
    OleDbConnection オブジェクトからだと、無名パラメーターしか使えないんですよね…。
    ACEDAO 経由で呼ぶ場合は名前付きにできるのですが。
    https://docs.microsoft.com/ja-jp/office/client-developer/access/desktop-database-reference/parameters-declaration-microsoft-access-sql


    > 「苗字 IS NULL」は、レコードの苗字列の値がDbNullの場合はTrueを返すという事は理解していますが、「? = 1」の意味が解りません。

    空文字列と NULL を区別するための措置です。

    たとえば
     WHERE (? = 1 AND 苗字 IS NULL) OR (苗字 = ?)
    という部分を
     WHERE ([引数1] = 1 AND 苗字 IS NULL) OR (苗字 = [引数2])
    のように読み替えてみます。

    そのうえで、VB 側からは
     Dim 引数1 As Integer, 引数2 As String
     If NULLをセットしたい場合 Then
      引数1 = 1
      引数2 = Nothing '未使用
     Else
      引数1 = 0
      引数2 = TextBox1.Text
     End If
    のような引数が渡されるイメージです。
違反を報告
引用返信
■35090 / ResNo.2)  Re[2]: CommandBuilderによって作られるCommandTextの内容
□投稿者/ Wan 付き人(67回)-(2022/06/28(Tue) 20:14:25)
  • アイコン
    魔界の仮面弁士様
    いつも丁寧がご指導ありがとうございます。
    
    折角教えて頂いたのですが、私の理解力が追いつきません。
    CommandBuilderで、CommandTextを取得した時にに設定されるParameterのプロパティは次のようになっています。
    DeleteCommanndのみ記載
    Paramete
    Name	DbType	OleDbType	SourceColumn	Direction	SourceVersion	Value
    p1	Int32{11}	Integer{3}	ID	Input{1}	Original{256}	Nothing
    p2	String(16)	VarWChar{202}	苗字	Input{1}	Original{256}	Nothing
    p3	String(16)	VarWChar{202}	苗字	Input{1}	Original{256}	Nothing
    p4	String(16)	VarWChar{202}	名前	Input{1}	Original{256}	Nothing
    p5	String(16)	VarWChar{202}	名前	Input{1}	Original{256}	Nothing
    p6	Decimal(7)	Numerid{113}	年齢	Input{1}	Original{256}	Nothing
    p7	Decimal(7)	Numerid{113}	年齢	Input{1}	Original{256}	Nothing
    
    これを見ると、引数1と引数2は同じ値になり、しかも、苗字と名前に関してはString型と1の比較を行っていることになります。
    Dim Str1 As String = "山田"
    If Str1 = 1 Then
     〜省略〜
    End If
    とすると: 'String "山田" から型 'Double' への変換は無効です。'
    となります。
    SQL文では、文字列と数値が比較できるのでしょうか?
    お手を煩わせます。

違反を報告
引用返信
■35091 / ResNo.3)  Re[1]: CommandBuilderによって作られるCommandTextの内容
□投稿者/ 魔界の仮面弁士 大御所(1431回)-(2022/06/28(Tue) 20:51:37)
  • アイコン
    No35088に返信(Wanさんの記事)
    > 'UPD_ Cmd.CommandText :UPDATE 既存テーブル SET 苗字 = ?, 名前 = ?, 年齢 = ? 
    > WHERE ((ID = ?) AND 
    > ((? = 1 AND 苗字 IS NULL) OR (苗字 = ?)) AND 
    > ((? = 1 AND 名前 IS NULL) OR (名前 = ?)) AND 
    > ((? = 1 AND 年齢 IS NULL) OR (年齢 = ?)))
    
    No35089 の機能は、SourceColumnNullMapping プロパティによって制御されています。
    
    Dim sb As New System.Text.StringBuilder()
    sb.AppendLine($"UpdateCommand のパラメータ数={UPD_Cmd.Parameters.Count}")
    For Each p As OleDbParameter In UPD_Cmd.Parameters
        sb.Append($"{p.ParameterName,-4}{vbTab}")
        sb.Append($"{p.SourceVersion,-8}{vbTab}")
        sb.Append($"{If(p.SourceColumnNullMapping, "T", "F")}{vbTab}")
        sb.Append($"{p.OleDbType,-8}{vbTab}")
        sb.AppendLine($"{p.SourceColumn}")
    Next
    Debug.WriteLine(sb.ToString())
    
    上記を実行すると、このような表が得られます。
    p1,p5,p6 の違いに着目してみてください。
    
    ================================================
    UpdateCommand のパラメータ数=10
    p1    Current    F   VarWChar  苗字
    p2    Current    F   VarWChar  名前
    p3    Current    F   Numeric   年齢
    p4    Original   F   Integer   ID
    p5    Original   T   Integer   苗字
    p6    Original   F   VarWChar  苗字
    p7    Original   T   Integer   名前
    p8    Original   F   VarWChar  名前
    p9    Original   T   Integer   年齢
    p10   Original   F   Numeric   年齢
    ================================================
    
    Original は SELECT した時点の元の値を意味し、
    Current は、これから反映させたい編集後の値です。
    
    「p5 と p6」「p7 と p8」「p9 と p10」では、
    SourceColumn は同じですが、
    SourceColumnNullMapping が異なっていますよね。これが
     (? = 1 AND {SourceColumn} IS NULL) OR ({SourceColumn} = ?)
    の正体となります。
    
    
    --- 以下蛇足 ---
    > インスタンス名	Access2010
    Access 2010 世代のプロバイダー名は、本来は
    "Microsoft.ACE.OLEDB.12.0" ですね。もちろん
    "Microsoft.ACE.OLEDB.16.0" からでもアクセス可能ですが。
    
    
    > Dim oledb As String = "Microsoft.ACE.OLEDB.16.0;"
    oledb という変数名を付けて後で、それと同名の
    > Dim Cn As New OleDb.OleDbConnection(…
    な OleDb 名前空間を記述されていますね。
    名前が被って分かりにくくなりませんか?
    
    それ以外の
    > Dim Da As New OleDbDataAdapter(…
    > Dim builder As OleDbCommandBuilder = …
    では、OleDb. が無い状態にそろえてあるのに対し、
    oledb 変数名が必要なところだけが意図的に
    OleDb. 付きの表記なので、ちょっと混乱しそうです。
    もちろん、文法的には問題ないのですけれども。
    
    
    > Dim Cn As New OleDb.OleDbConnection($"Provider={oledb} Data Source={acfile}")
    プロバイダー名にセミコロンを入れるのは不自然ですね。
     Dim oledb As String = "Microsoft.ACE.OLEDB.16.0;"
     $"Provider={oledb} Data Source={acfile}"
    よりは
     Dim oledb As String = "Microsoft.ACE.OLEDB.16.0"
     $"Provider={oledb};Data Source={acfile}"
    の方が好ましいですよ。他のパラメーターもセミコロン区切りなので。
    
    実際のところ、接続文字列は
     Dim csb As New OleDbConnectionStringBuilder()
     csb.Provider = "Microsoft.ACE.OLEDB.16.0"
     csb.DataSource = "D:\データベース勉強用DB\INSERT文.accdb"
     Dim Cn As New OleDbConnection(csb.ConnectionString)
    のようにして組み立てることもできるのですが、この際に
     csb.Provider = "Microsoft.ACE.OLEDB.16.0;"
    としてしまうと、正しく接続できなくなります。
    
    
    > Dim Da As New OleDbDataAdapter("SELECT * FROM 既存テーブル", Cn)
    [既存テーブル] なのですね。冒頭の記述から [Test] かと誤解してました。
    
    > (Accessのテーブル構成)
    > インスタンス名	Access2010
    > データベース名	データベース勉強用DB
    > 論理テーブル名	Test
    > 物理テーブル名	INSERT文.accdb

違反を報告
引用返信
■35092 / ResNo.4)  Re[2]: CommandBuilderによって作られるCommandTextの内容
□投稿者/ 魔界の仮面弁士 大御所(1432回)-(2022/06/28(Tue) 21:11:34)
  • アイコン
    No35091に追記(魔界の仮面弁士の記事)
    > No35089 の機能は、SourceColumnNullMapping プロパティによって制御されています。
    
    おぉ。追加説明のコードを書いているうちに、
    ピンポイントでその点についての追加質問が投稿されていた…!
    
    
    SQL における「列名 = 値」という記述について考えてみます。
    
    SET などの『代入処理』の場合は、
    値が null/非null いずれでも、「列名 = 値」と書けます。
    
    しかし、WHERE などの『比較処理』の場合は、
    「列名 = NULL」では TRUE 判定されないため、
    「列名 = 非NULL値」と「列名 IS NULL」を使い分けねばなりません。
    そのための仕組みです。
    
    
    ついでなので、DELETE と INSERT のケースも載せておきます。
    
    DeleteCommand のパラメータ数=7
    p1      Original    F   Integer     ID
    p2      Original    T   Integer     苗字
    p3      Original    F   VarWChar    苗字
    p4      Original    T   Integer     名前
    p5      Original    F   VarWChar    名前
    p6      Original    T   Integer     年齢
    p7      Original    F   Numeric     年齢
    
    
    InsertCommand のパラメータ数=3
    p1  	Current 	F	VarWChar	苗字
    p2  	Current 	F	VarWChar	名前
    p3  	Current 	F	Numeric 	年齢
    
    
    DataTable 内のデータは、DataRowVersion によってバージョン管理されており、
    SELECT 直後の値(Original)と
    編集結果を考慮した現在値(Current)の 2 種類を持ちます。
    ※ DataRow の RowState プロパティも参照
    
    
    Original なパラメーターは、WHERE 句のために使われます。
    INSERT の場合は WHERE が無いので、Current のみです。
    
    逆に DELETE の場合は、現在値が存在しないため Current がなく
    Original だけになります。
    
    そして UPDATE の場合は、SET 句用の Current と
    WHERE 句用の Original の両方があるというわけです。

違反を報告
引用返信
■35097 / ResNo.5)  Re[3]: CommandBuilderによって作られるCommandTextの内容
□投稿者/ Wan 付き人(68回)-(2022/07/07(Thu) 09:46:35)
  • アイコン魔界の仮面弁士さま
    お礼が大変遅くなりすみません。
    下記の部分が理解できずに、色々勉強していました。

    > 「苗字 IS NULL」は、レコードの苗字列の値がDbNullの場合はTrueを返すという事は理解していますが、「? = 1」の意味が解りません。
    空文字列と NULL を区別するための措置です。

    取り合えず、データベースの列がNull許容型で、且つ、データがNullの場合Trueとすると理解してこの質問のFixとして、勉強を進める過程で、再度、質問するかもしれませんが、その時は宜しくお願い致します。

    丁寧に、コード迄書いていただいて有難うございました。

解決み!
違反を報告
引用返信

■記事リスト / レス記事表示 → [親記事-5]



■記事リスト / ▼下のスレッド / ▲上のスレッド
■34964 / 親記事)  DataGridViewの特定セルにボタンを配置する方法
□投稿者/ り 一般人(4回)-(2021/11/17(Wed) 16:05:58)
  • アイコン環境/言語:[C#] 
    分類:[.NET] 

    画像のような表を作成したいのですが、
    特定のセルにのみボタンを配置することは可能でしょうか。
548×394 => 250×179
イメージ
IMAGE.png
/6KB
違反を報告
引用返信

▽[全レス5件(ResNo.1-5 表示)]
■34965 / ResNo.1)  Re[1]: DataGridViewの特定セルにボタンを配置する方法
□投稿者/ 魔界の仮面弁士 大御所(1411回)-(2021/11/17(Wed) 18:12:54)
  • アイコンNo34964に返信(りさんの記事)
    > 画像のような表を作成したいのですが、
    > 特定のセルにのみボタンを配置することは可能でしょうか。

    dataGridView1[0, 0] = new DataGridViewButtonCell { UseColumnTextForButtonValue = true };
違反を報告
引用返信
■34966 / ResNo.2)  Re[2]: DataGridViewの特定セルにボタンを配置する方法
□投稿者/ り 一般人(5回)-(2021/11/19(Fri) 08:52:28)
  • アイコンNo34965に返信(魔界の仮面弁士さんの記事)
    > ■No34964に返信(りさんの記事)
    >>画像のような表を作成したいのですが、
    >>特定のセルにのみボタンを配置することは可能でしょうか。
    >
    > dataGridView1[0, 0] = new DataGridViewButtonCell { UseColumnTextForButtonValue = true };

    返信遅くなりました。
    早急に回答していただきありがとうございます!
    しかし、私の理解不足だと思うのですが、これだけでは実現できませんでした。
    他に記述すべき内容がありましたら、教えていただきたいです...
違反を報告
引用返信
■34974 / ResNo.3)  Re[3]: DataGridViewの特定セルにボタンを配置する方法
□投稿者/ り 一般人(6回)-(2021/12/06(Mon) 11:35:47)
  • アイコン試行錯誤したらできました。
解決み!
違反を報告
引用返信
■35338 / ResNo.4)  Re[4]: DataGridViewの特定セルにボタンを配置する方法
□投稿者/ なかい 一般人(1回)-(2023/01/18(Wed) 20:47:46)
  • アイコンNo34974に返信(りさんの記事)
    > 試行錯誤したらできました。

    お世話様です。
    どのようにして実現できましたのでしょうか?
    同じようなことで試行錯誤しています。
    教えていただけたら、ありがたいです。

違反を報告
引用返信
■35339 / ResNo.5)  Re[5]: DataGridViewの特定セルにボタンを配置する方法
□投稿者/ 魔界の仮面弁士 大御所(1521回)-(2023/01/19(Thu) 08:56:36)
  • アイコンNo35338に返信(なかいさんの記事)
    > どのようにして実現できましたのでしょうか?
    > 同じようなことで試行錯誤しています。
    > 教えていただけたら、ありがたいです。

    他者が解決済みとしているスレッドを未解決に戻して質問するのではなく、
    新たなスレッドを立ち上げたうえで、そちらで質問していただけますでしょうか。
    (投稿時に、このスレッドの URL もしくは投稿 No を貼ってもらえると助かります)

    なお、質問する際には
     ・言語指定(VB なのか C# なのか)
     ・Visual Studio のバージョン
     ・現状、どこで問題が起きているのか、あるいは No34965 のどこが分からないか
    などを明記していただけますようお願いします。

    申し訳ありませんが、こちらのスレッドは解決済みに戻させていただきます。
解決み!
違反を報告
引用返信

■記事リスト / レス記事表示 → [親記事-5]



■記事リスト / ▼下のスレッド / ▲上のスレッド
■35535 / 親記事)  WebView2によるスクレ―ピング
□投稿者/ Wan 付き人(81回)-(2023/11/10(Fri) 17:06:14)
  • アイコン環境/言語:[VisualBasic2019 Windows10 Basic Framework4.7.2] 
    分類:[.NET] 

    WebView2を使って、スクレ―ピングを考えています。クラス名でTableを抽出しtrとtdで構成された表をJavaScriptで二次元配列に代入し、returnで返してたつもりです。が、DataTableの変数で受け取れません。途方に暮れています。どなたか?詳しい方いらっしゃいましたら教えて頂けないでしょうか?
    スクレ―ピングについては、複数ページに渡るので、WebView2_NavigationCompletedが発生するたびに、DataTableに追加し続けるコードにしたいのが最終目標です。

    Dim DataTable_Scraping As New DataTable
    DataGridView1.DataSource = DataTable_Scraping

    Private Async Sub WebView2_NavigationCompleted(sender As Object, e As CoreWebView2NavigationCompletedEventArgs) Handles WebView21.NavigationCompleted
    Dim js As New System.Text.StringBuilder
    js.AppendLine("const hyou=[];let i=0;")
    js.AppendLine("var TrElems = document.getElementsByClassName('Tableが含まれるクラス名')[0].getElementsByTagName('tr');")
    js.AppendLine("Array.prototype.forEach.call(TrElems, function(TrElem) {")
    js.AppendLine(" hyou.push([]);")
    js.AppendLine(" var TdElems = TrElem.getElementsByTagName('td');")
    js.AppendLine(" Array.prototype.forEach.call(TdElems, function(TdElem) {")
    js.AppendLine(" hyou[i].push(TdElem.textContent);")
    js.AppendLine(" });")
    js.AppendLine(" i=i+1;")
    js.AppendLine("});")
    js.AppendLine("return hyou;")

    DataTable_Scraping = Await WebView21.ExecuteScriptAsync(js.ToString())
    '読み込み結果を判定
    If e.IsSuccess Then
         ‘ここで次のページへの移動用の要素をクリックしている。動作確認済み
         ‘getElementsByClassName('****')の要素数が1の場合は、終わり
    Await WebView21.ExecuteScriptAsync(
    "document.getElementsByClassName('****')[1].getElementsByTagName('a')[0].click();")
    Else
    Console.WriteLine(e.WebErrorStatus)
    End If
    End Sub

違反を報告
引用返信

▽[全レス4件(ResNo.1-4 表示)]
■35536 / ResNo.1)  Re[1]: WebView2によるスクレ―ピング
□投稿者/ Wan 付き人(82回)-(2023/11/10(Fri) 17:16:18)
  • アイコン追伸

    return hyou;の部分を
    console.table(hyou)とすると
    Edgeの開発者ツール-コンソールで動かして表として表示されますので、
    JavaScript上では、表形式になっているようです。

    また、varをletやconstに変えると、Edgeのコンソール上でも、上手く動かない理由も教えて頂ければ幸いです。



違反を報告
引用返信
■35537 / ResNo.2)  Re[2]: WebView2によるスクレ―ピング
□投稿者/ Hongliang 大御所(646回)-(2023/11/11(Sat) 18:36:02)
  • アイコンVisual Studio 2015から複数行リテラルを扱えるようになったので、文字列が固定であれば変にStringBuilder使うよりリテラルで書いた方が見やすいしパフォーマンスも良いです。

    ExecuteScryptAsyncで実行されるスクリプトは、最後の式を評価してそれを返値とするような挙動になります。
    なので、変数hyouの内容を返値としたいのであれば、単に変数を記述します。
    × return hyou;
    ○ hyou;
    あるいは、以下のように無名関数の呼び出しに全体を変換する方法もあります。
    js = "(function() {
    const hyou = [];
    色々処理する;
    return hyou; })()"

    https://learn.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2.executescriptasync?view=webview2-dotnet-1.0.2088.41
    ExecuteScriptAsyncの返値(Await結果)は文字列、String型です。
    当然ながらDataTable型の変数に直接代入することはできません。
    この文字列はスクリプトの結果をJSON.stringify()したJSON形式なので、一般的にはデシリアライズして.NET上のオブジェクトとして扱います。
    JSONのデシリアライザとしては、System.Text.JsonでもJson.NETでもお好みのものを使えばいいでしょう。.NET 4.xで組み込みなのはDataContractJsonSerializerというのがありましたっけ。
    ざっと見た様子では、JavaScript上では「「文字列の配列」の配列」のようなので、VB上ではString型の配列の配列、つまり String()() 型としてデシリアライズできます。
    DataTableへはこのString()()から手動で移し替えてください。

    > また、varをletやconstに変えると、Edgeのコンソール上でも、上手く動かない理由も教えて頂ければ幸いです。
    ExecuteScriptAsycで渡したJavaScript内で定義したりした変数はそのまま残ります。
    constやletで宣言した変数は再宣言不可能なので、もう一度ExecuteScriptAsyncしたりするとエラーになります。
    ちなみにconstにせよletにせよブロックスコープなので、上の方で示した無名関数を使う場合、
    (function() { const hyou = []; ... })()
    このhyouはこの無名関数内でのみ有効なので、再度呼び出しても問題ありません。

    何度も使用するJavaScript関数なら、
    CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync
    で登録しておけば便利です。
違反を報告
引用返信
■35538 / ResNo.3)  Re[1]: WebView2によるスクレ―ピング
□投稿者/ 魔界の仮面弁士 大御所(1566回)-(2023/11/11(Sat) 22:04:19)
  • アイコン
    No35535に返信(Wanさんの記事)
    > スクレ―ピング
    「スクレーピング」が
    「スクレ―ピング」になっていて
    似非日本語感を微妙に覚えるなど(
    
    
    > WebView2を使って、スクレ―ピングを考えています。
    RSS をクロールするだけでで要件を満たせるなら、
    XDocument だけで簡単に済むのですけれどね…。
    ひとまず、ここの掲示板の RSS を拾ってみた例。
    
    
    Imports System.Xml.Linq
    Public Class Form1
        Private WithEvents dgv As DataGridView
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            dgv = New DataGridView() With {.Dock = DockStyle.Fill, .ReadOnly = True, .AllowUserToAddRows = False}
            Controls.Add(dgv)
            Dim doc = XDocument.Load("https://dobon.net/cgi-bin/vbbbs/rss.cgi?ver=2.0")
            Dim items = From item In doc...<item>
                        Select item.<title>.Value,
                            item.<link>.Value,
                            pubDate = Date.Parse(item.<pubDate>.Value),
                            item.<description>.Value
            dgv.DataSource = items.ToArray()
        End Sub
    End Class
    
    
    こちらは、Web ページからスクレイピングする場合。
    
    Imports Microsoft.Web.WebView2.Core
    Imports Microsoft.Web.WebView2.WinForms
    Public Class Form1
        Private WithEvents wv As WebView2
        Private WithEvents ds As DataSet
        Private WithEvents tbl As DataTable
        Private WithEvents dgv As DataGridView
    
        Private Async Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
            ds = New DataSet()
            tbl = ds.Tables.Add("dobon")
            wv = New WebView2 With {.Visible = False}
            dgv = New DataGridView() With {.Dock = DockStyle.Fill, .ReadOnly = True, .AllowUserToAddRows = False}
            dgv.DataSource = tbl
    
            tbl.PrimaryKey = New DataColumn() {tbl.Columns.Add("Id", GetType(Integer))}
            tbl.Columns.Add("Solved", GetType(Boolean)).DefaultValue = False
            tbl.Columns.Add("Title")
            tbl.Columns.Add("Category")
            tbl.Columns.Add("FirstAuthor")
            tbl.Columns.Add("FirstPostAt")
            tbl.Columns.Add("LastAuthor")
            tbl.Columns.Add("LastPostAt")
            Controls.AddRange(New Control() {dgv, wv})
    
            Await wv.EnsureCoreWebView2Async()
            'wv.CoreWebView2.Navigate("https://dobon.net/cgi-bin/vbbbs/rss.cgi?ver=2.0")
            wv.CoreWebView2.Navigate("https://dobon.net/cgi-bin/vbbbs/cbbs.cgi?H=F&no=0")
        End Sub
        Private Async Sub wv_NavigationCompleted(sender As Object, e As CoreWebView2NavigationCompletedEventArgs) Handles wv.NavigationCompleted
            Dim js = "(()=>{
                const table=[];
                document.querySelectorAll('TABLE.topiclist').forEach(t=>{
                    [...t.rows].slice(1).forEach(tr=>{
                        const cols=[...tr.cells];
                        const d=[];
                        d[0]=cols[1].querySelector('small>font').innerText.substr(1)*1;
                        d[1]=cols[6].innerText.includes('済');
                        d[2]=cols[1].firstChild.innerText;
                        d[3]=cols[0].innerText;
                        d[4]=cols[3].innerText;
                        d[5]=cols[1].querySelector('small').lastChild.substringData(5,16);
                        d[6]=cols[4].innerText
                        d[7]=cols[5].innerText;
                        table.push(d);
                    });
                });
                return table;
            })();"
    
            Dim result = Await wv.CoreWebView2.ExecuteScriptAsync(js)
            Dim ary = Newtonsoft.Json.JsonConvert.DeserializeObject(Of Object()())(result)
            ds.EnforceConstraints = False
            Array.ForEach(ary, AddressOf tbl.Rows.Add)
            ds.EnforceConstraints = True
        End Sub
    End Class

違反を報告
引用返信
■35539 / ResNo.4)  Re[3]: WebView2によるスクレ―ピング
□投稿者/ Wan 付き人(83回)-(2023/11/12(Sun) 10:51:31)
  • アイコンHongliang様
    いつも、丁寧なご指導ありがとうございます。

    ご指摘のように、
    retrn hyou → hyouにしたら返り値が取れました。

    教えて頂いた内容を熟読して、取得した返り値を加工していきたいと思います。

    ありがとうございました。
解決み!
違反を報告
引用返信

■記事リスト / レス記事表示 → [親記事-4]



■記事リスト / ▼下のスレッド / ▲上のスレッド
■35461 / 親記事)  C#でJpeg圧縮のTiffファイルを作成したい
□投稿者/ たろう 一般人(1回)-(2023/06/26(Mon) 10:58:52)
  • アイコン環境/言語:[Windows10 / C# / VisualStudio2015 / .Net Framework4.0] 
    分類:[.NET] 

    過去、Visual Studio 2015を使って、Tiffファイルを作成するアプリケーションを作成しました。

    最近になって「LEADTOOLSではJpeg圧縮のTiffファイルが作れるのに、あなたのソフトではできないのか?」といった問い合わせをもらいました。
    どうやらTiffでイメージ保存をしたいが、カラー画像だとサイズが大きいので画像はJpegにしたい(でもファイル形式はTiffのまま)ということのようです。

    私が作成した保存処理はTiffBitmapEncoderを使用しており、Compressionプロパティにセットできるものを調べるとJpegはありませんでした。

    有料のライブラリなどを使用せず、Jpeg圧縮のTiffファイルを保存する方法はないものでしょうか。
    (LEADTOOLSはライセンス料が高額なため使用したくない、という理由で.Netの機能を使用して画像保存を作成した経緯があります)

違反を報告
引用返信

▽[全レス4件(ResNo.1-4 表示)]
■35462 / ResNo.1)  Re[1]: C#でJpeg圧縮のTiffファイルを作成したい
□投稿者/ Hongliang 大御所(643回)-(2023/06/26(Mon) 12:48:38)
  • アイコンとりあえず、Windows 10 22H2では、 TiffBitmapEncoderを使っては無理みたいですね。
    // System.Windows.Media.Imaging.TiffCompressOptionには未定義の7というのも指定可能でしたが、これもLZWベースのようです。
    System.Drawingの方でも有効そうなものは見つからないので、少なくとも現時点では、恐らく.NET標準ライブラリでは扱えないでしょう。

    // System.Windows.Media.ImagingにせよSystem.DrawingにせよOSの機能をそのまま呼び出しているだけなので、そのうちWindowsのTIFFエンコーダがサポートするようになる可能性はゼロではないですが、期待薄と思います。

    どうしてもというなら、何らかのサードパーティ製ライブラリを使用するしかないでしょうね。
    NugetにはいくつかTIFFのライブラリがあるようです。ライセンスを確認の上で試されてみてはいかがでしょうか。
違反を報告
引用返信
■35463 / ResNo.2)  Re[2]: C#でJpeg圧縮のTiffファイルを作成したい
□投稿者/ たろう 一般人(2回)-(2023/06/26(Mon) 16:47:50)
  • アイコンNo35462に返信(Hongliangさんの記事)

    > どうしてもというなら、何らかのサードパーティ製ライブラリを使用するしかないでしょうね。
    > NugetにはいくつかTIFFのライブラリがあるようです。ライセンスを確認の上で試されてみてはいかがでしょうか。

    なるほど、やはり現在の.Netの標準ライブラリでは無理そうですね。
    商用利用もできて、安価もしくは無料で利用できるライブラリがないか探してみます。


違反を報告
引用返信
■35464 / ResNo.3)  Re[3]: C#でJpeg圧縮のTiffファイルを作成したい
□投稿者/ KOZ 一般人(20回)-(2023/06/27(Tue) 09:33:53)
  • アイコン
    2023/06/27(Tue) 09:36:20 編集(投稿者)
    
    ■No35463に返信(たろうさんの記事)
    
    Magick.NET でイケるようです。(ライセンスは Apache License 2.0)
    NuGet から Magick.NET.Core と Magick.NET-Q16-AnyCPU をインストールしてください。
    
    using ImageMagick;
    static class Program
    {
        [STAThread]
        static void Main() {
            using (MagickImage image = new MagickImage(@"z:\temp\test.png")) {
                image.Format = MagickFormat.Tiff;
                image.Settings.Compression = CompressionMethod.JPEG;
                image.Write(@"z:\temp\test.tif");
            }
        }
    }
    

違反を報告
引用返信
■35465 / ResNo.4)  Re[4]: C#でJpeg圧縮のTiffファイルを作成したい
□投稿者/ たろう 一般人(3回)-(2023/06/27(Tue) 15:47:44)
  • アイコンNo35464に返信(KOZさんの記事)
    > Magick.NET でイケるようです。(ライセンスは Apache License 2.0)


    情報ありがとうございます!
    試してみます。


解決み!
違反を報告
引用返信

■記事リスト / レス記事表示 → [親記事-4]



■記事リスト / ▲上のスレッド
■35451 / 親記事)  DataGridViewのVirtualModeを有効した場合の実装方法
□投稿者/ 炎の妖精さん 一般人(27回)-(2023/06/12(Mon) 13:30:32)
  • アイコン環境/言語:[Win10/VB.NET/Framework3.5/VS2010] 
    分類:[.NET] 

    お世話になり、いつも助けていただき感謝です。
    此度の件もお付き合いいただければ恐縮です。

    DataGridViewに約50〜1000万件のデータを表示させたいと考えており、
    DataTableに膨大なデータを挿入して、DataGridViewのDataSourceを設定すると"system.outofmemoryexception"のエラーが発生します。
    ネットで調べると仮想モード(VirtualMode)を有効にするとメモリ使用量を抑えることが出来るとの記載があった為、試しに実装しました。
    ●技術レポート「DataGridViewコントロールのVirtualMode(仮想モード)について」
    https://www.softech.co.jp/mm_200506_tr.htm

    今回はデータを表示させたいだけであり、新規行や削除、値の変更は全くありませんので"DataGridView.CellValueNeeded"のみの実装で良いかなと思いましたので
    実装したのですが、状況は変わらずメモリ不足のエラーが発生しました。

    どのように実装すればメモリ消費を抑えるコードが書けるのでしょうか?
    恐縮ですが、何卒よろしくお願いいたします。
違反を報告
引用返信

▽[全レス4件(ResNo.1-4 表示)]
■35453 / ResNo.1)  Re[1]: DataGridViewのVirtualModeを有効した場合の実装方法
□投稿者/ 魔界の仮面弁士 大御所(1553回)-(2023/06/12(Mon) 16:00:50)
  • アイコン
    No35451に返信(炎の妖精さんさんの記事)
    > DataGridViewに約50〜1000万件のデータを表示させたいと考えており、
    仮に 1 レコード当たり 32 バイト程度のデータであったとしても、
    1000万レコードあったら、300MB 級のデータサイズになりますね。

    これらが Web Service として通信される場合、JSON や XML 化のために
    さらに数倍のデータ量が要求されることになるかもしれません。


    > ネットで調べると仮想モード(VirtualMode)を有効にするとメモリ使用量を抑えることが出来るとの記載があった為、試しに実装しました。
    どのように実装しましたか。
    実際に試せるような実験コードが提示されていないので、
    以下、概要のみの回答となりますが:


    > DataTableに膨大なデータを挿入して、DataGridViewのDataSourceを設定すると"system.outofmemoryexception"のエラーが発生します。
    DataGridView の仮想モードであれ、ListView の仮想モードであれ、
    そもそも 1000万件のデータを画面に表示して、そのすべてをスクロールして
    その 1件 1件をすべて閲覧するという事は非常に稀であり、
    実際に必要なデータはごく一部だけであろうかと思います。

    なので仮想モードにおいては、「現在見えているページ」、「スクロールで要求されたページ」のための
    必要最小限の小さなデータを、必要に応じてサーバーから動的に読み込むという実装をとります。
    Google Map で地図をスクロールするたびに Web 通信が行われる状況に似ていますね。

    一度読み込んだデータでも、別の領域をロードしたらまた忘れられてしまうので、
    以前の情報をとっておきたい場合は、独自のキャッシュ処理を追加します。
    (いずれにしても、大量データを保持し過ぎることが無いような設計が求められます)
    https://learn.microsoft.com/ja-jp/dotnet/desktop/winforms/controls/virtual-mode-with-just-in-time-data-loading-in-the-datagrid?view=netframeworkdesktop-4.8
違反を報告
引用返信
■35454 / ResNo.2)  Re[2]: DataGridViewのVirtualModeを有効した場合の実装方法
□投稿者/ 魔界の仮面弁士 大御所(1554回)-(2023/06/12(Mon) 16:11:32)
  • アイコンNo35453に追記(魔界の仮面弁士の記事)
    > (いずれにしても、大量データを保持し過ぎることが無いような設計が求められます)
    > https://learn.microsoft.com/ja-jp/dotnet/desktop/winforms/controls/virtual-mode-with-just-in-time-data-loading-in-the-datagrid?view=netframeworkdesktop-4.8


    上記サンプルの場合、表示領域に合わせて、

    Select Top 【rowsPerPage】列1, 列2, 列3, …
    From テーブル名
    Where ソート条件列 NOT IN
    (
     Select Top 【lowerPageBoundary】 ソート条件列
     From テーブル名
     Order By ソート条件列
    )
    Order By ソート条件列

    という SQL Server への問い合わせが行われる想定ですね。
違反を報告
引用返信
■35455 / ResNo.3)  Re[3]: DataGridViewのVirtualModeを有効した場合の実装方法
□投稿者/ 魔界の仮面弁士 大御所(1555回)-(2023/06/12(Mon) 19:00:19)
  • アイコンNo35454に追記(魔界の仮面弁士の記事)
    > 上記サンプルの場合、表示領域に合わせて、
    > という SQL Server への問い合わせが行われる想定ですね。

    SQL Server 2012 以降や Oracle12c以降であれば、
    ORDER BY 句 で OFFSET と FETCH を使うことでページングできます。
    https://sql55.com/query/paging-query-results.php

    ページ指定での分割読取り手法は、お使いのデータベースによって
    使用可能な構文も異なるでしょうし、そこは随時調整してください。
違反を報告
引用返信
■35457 / ResNo.4)  Re[4]: DataGridViewのVirtualModeを有効した場合の実装方法
□投稿者/ 炎の妖精さん 一般人(28回)-(2023/06/13(Tue) 11:18:22)
  • アイコン魔界の仮面弁士様
    いつも助けていただきまして、ありがとうございます。

    > ■No35454に追記(魔界の仮面弁士の記事)
    >> 上記サンプルの場合、表示領域に合わせて、
    >> という SQL Server への問い合わせが行われる想定ですね。
    >
    > SQL Server 2012 以降や Oracle12c以降であれば、
    > ORDER BY 句 で OFFSET と FETCH を使うことでページングできます。
    > https://sql55.com/query/paging-query-results.php
    >
    > ページ指定での分割読取り手法は、お使いのデータベースによって
    > 使用可能な構文も異なるでしょうし、そこは随時調整してください。

    イメージとしましてはECサイトの検索画面のような感じでしょうか?
    1ページで20,30件を表示させ、ページ送りが出来るようなイメージです。

    その手法をとるなら、やりたいことが実現できるかも知れません。
    一度、検討させていただきます。

解決み!
違反を報告
引用返信

■記事リスト / レス記事表示 → [親記事-4]






Mode/  Pass/


- Child Tree -