2012年12月9日 星期日

PLSQL Developer 如何連上 Oracle 11g

PLSQL Developer 是使用 Oracle 的方便工具,
但是很尷尬的是,每次我的 Oracle Server 裝起來之後,
我的 PLSQL Developer 每次都連不上 Oracle Server !!!
照著公司的文件設定試了好多次都不行,
後來在網路上找到一篇文章,總算是有解答出我的疑惑!

原來是因為 PLSQL Developer 沒辦法執行 64bit 的 oci.dll,
但是 Win7 x64 又只能安裝 64bit 的 Oracle ,所以這樣就無解啦!

解法就是去下載一個 Oracle Instant client x32
將 PLSQL Developer 指定到 Oracle Instant client x32 的 oci.dll,
然後再設定一些環境變數就可以執行了!

設定環境變數

進入【控制台\系統及安全性\系統\進階系統設定】點選【環境變數】。


2012年11月15日 星期四

Oracle - 密碼忘記怎麼處理?

不知道該怎麼說,
怎麼每次裝完 Oracle 之後怎麼樣都登入不進去?
查了一下可以用以下的做法更改密碼。



C:\Users\Frankie>sqlplus / as sysdba

SQL*Plus: Release 11.2.0.1.0 Production on 星期四 11月 15 17:55:12 2012

Copyright (c) 1982, 2010, Oracle.  All rights reserved.


連線到:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL> alter user sys identified by chen1976$;

已更改使用者.

SQL> alter user system identified by chen1976$;

已更改使用者.

SQL>


我猜可能是安裝的時候我的密碼不符合 Oracle 的安全性要求吧?

2012年9月6日 星期四

C# - 如何知道泛型的型態?

因為某種需要,所以開了一個 table ,
在裡面的開了一個 varchar 的欄位,
雖然是 varchar 的型態,
但是實際上會存入各種資料型態 bool, int, decimal, string...
原本以前的笨蛋寫法會是像是下面這種直接回傳字串的宣告,


public string GetOptionValue(string optionName)


然後呼叫的人再去把字串轉型成自己要的型態。

不過我是一個很懶的人,
所以我想說如果每次要用的人都自己還要轉型,
我實在是很懶得每次都還要寫一樣的 code ,
雖然可能只是多了一行,但是我就是不爽寫!
那可以怎麼做呢?
這個時候我想到了也許可以利用泛型來處理,
泛型的宣告如下,


public T GetOptionValue<T>(string optionName)


2012年8月28日 星期二

C# - Threading using Task


之前在【C# Threading Finial】裡面已經把目前我所知道 Threading 跟 UI 配合的方法 demo 了一次,
上次同事告訴我說在 .net 4.0 (VS2010) 裡面提供了一個新的方式 Task 來寫 Threading ,
所以我就把上次【C# Threading Finial】裡面的程式拿來改成用 Task 的方式,
測試了一下,的確是簡單了許多,
不過規矩還是一樣,跟 UI 的互動還是得交給主執行緒,
所以還是得用 Invoke 的方式來呼叫,
其實我覺得比較麻煩的還是跟 UI 的互動,其他的倒是還好,
接下來就來看看上次那個程式怎麼修改成 Task 的方式吧!
首先原來的 btnThreadingQuery_Click 就變成下面這樣啦!
改成用 Task.Factory.StartNew 的方式來呼叫 QueryMain()


private void btnThreadingQuery_Click(object sender, EventArgs e)
{
    //ThreadPool.QueueUserWorkItem(new WaitCallback(QueryMain));
    Task.Factory.StartNew(() =>
    {
        QueryMain();
    });
}


然後主程式主要的修改如下:

2012年8月16日 星期四

C# - 如何複製其他物件的事件


之前遇到了要強制驅動物件的事件【C# 如何強制驅動物件的事件?】,
也遇到了要移除物件的事件【C# - 如何移除未知名稱的事件 - LookupEdit.KeyDown 】,
正所謂無三不成禮,這次要做的是複製其他物件的事件!
說複製其實不太對,正確地來說應該是把其他物件的事件掛(delegate)上來。

例如我們可能在 A 物件寫了一個 KeyDown 的程式,


private void ObjectA_KeyDown(object sender, KeyEventArgs e)


在 designer 裡面會是寫成這樣,


this. ObjectA.KeyDown += new
System.Windows.Forms.KeyEventHandler(this. ObjectA_KeyDown);


當我們的 B 物件也要用同一個事件的時候,我們只要手動用 += 就可以掛上這個事件了!
但是問題又來了,如果我們不知道他事件的名稱,那我們要怎掛?
其實前面一大段程式都跟之前移除事件的程式一樣,
只是後面要怎麼掛上去呢?說穿了很簡單!
(其實是會寫之後才覺得簡單 XD)
程式如下,跟之前程式最大的差別就是最後面兩行,

2012年8月10日 星期五

Oracle - Function return list

莫名其妙的開始要看 Oracle 的東西,
第一個遇到的難題就是要幫別人看 PL/SQL ,
但是我根本不會寫呀!
自從二技那堂 Oracle 的學分之後我就再也沒有摸過了,
連書都送別人了!可見我多麼有自信不會再摸到 Oracle 呀!
可是上天是愛捉弄人的!

anyway, 現在要弄得就是寫一個STORE PROCEDURE\FUNCTION 回傳一個 TABLE,
本來覺得這根本是天殺的簡單呀!
沒想到小朋友寫出來的卻是回傳一個 CURSOR !!!這是甚麼東!
結果才發現這邊的人居然沒有寫過這樣的東西,
還質疑說 Oracle 可以這樣子嗎?這問倒我了,我哪知道呀~~~
所以我就東查西查的,還問了阿輝仔!
原來 Oracle 真的不能直接回傳 SELECT * FROM xxx_table 這樣!
不過可以用間接的方式,往下看吧!

首先要先宣告你要回傳的 List Array 的 OBJECT:

CREATE TYPE O_GROUP AS OBJECT
(GROUP_ID VARCHAR2(8),
GROUP_NAME VARCHAR2(30));

然後接下來在將這個 OBJECT 轉成 TABLE:


GREATE TYPE GROUP_LIST AS TABLE OF O_GROUP;


然後就可以開始寫 Function 啦!如下:

2012年8月6日 星期一

更換程式圖示之後還是顯示舊的圖示的鬼問題!

一般我們辛苦寫完一個程式之後都會給程式一個小圖示,
以便拉出捷徑的時候可以有一個漂亮的圖示顯示在桌面上,
不過上星期我卻遇到一個軌問題,
就是呢........把舊的 icon 改掉之後拉出捷徑卻還是顯示舊的!
原本個人天真的以為這個可能是 windows 有 cache 住的關係,
所以使出萬法規宗的重開機大法應該就可以了吧?沒想到不管用!
在嘗試的同時,隔壁的同事說他之前有遇過,要去 registry 刪除,
打開 regedit 之後果然裡面有很多那隻程式名稱的機碼,
刪刪刪之後重開機.............還是不行!
所以就開始估狗囉!
只不過這個關鍵字還真的不知道該下甚麼,
不過後來有找到一篇
[Windows7]修復桌面與開始功能表中錯亂或是消失的捷徑圖示 - Ouch@點部落- 點部落
果然 windows 有 cache 住圖示,
依照該篇網誌的指示直接用 cmd 的模式切換到下面的目錄

CD C:\Users\Frankie\AppData\Local

然後 cache 的檔案叫 IconCache.db ,
但是因為他是隱藏的,所以要先解掉隱藏這件事情。

attrib -h IconCache.db

然後這樣才可以刪除它。

del IconCache.db

然後重開機,然後還是不行.........................
馬的,試了好幾次都還是不行,怪!難道是因為這支程式自己寫的關係嗎?
試了好多次,最後不管三七二十一,
我把 registry 裡面的程式名稱都刪除,也把 IconCache.db 刪除,準備跟它同歸於盡!
重開機之後居然OK了!
所以結論就是兩個都是刪除,為了這個浪費了我好多時間喔!
心想,如果客戶說要換圖示那不過搞死我了!
可能要在更新程式的時候順便做這件事情,然後叫客戶重開機?!?!
我覺得我應該會被打死,應該有重建 IconCache.db 的指令吧?
等我快被打死之前再來孤狗好了!

2012年7月14日 星期六

SQL - 中文長度的問題、LEN、DATALENGTH

因為轉檔的關係,有時候需要把名稱的欄位簡短後塞到簡稱的欄位去,
不過常常都會出現的狀況就是....



即便我已經用了 SUBSTRING 也是一樣!
但是我用 LEN 看一下 SUBSTRING 之後的長度明明就沒有超過呀?
後來上網查了一下有關 LEN 中文長度的搜尋,
然後找到了一個新的函數 DATALENGTH ,
大致上 LEN 的算法是中文算長度1、英文也算長度1,
然後 DATALENGTH 的算法是中文長度2、英文長度1,
中間的差異大概就是一個算字元數,一個算BYTE數吧?
所以當我寫出下面 SQL 的時候,算出來的數字是完全不一樣的!

LEN(name_ch) AS "LEN", DATALENGTH(name_ch) AS "DATALENGTH"



於是乎我就想說那 SUBSTRING 有沒有類似的函數可以用呢?
很遺憾的是我沒有找到,也許 SQL SERVER 2020 會支援吧?
所以當我寫下面那樣的話還是會出現二進位截斷的問題,

SUBSTRING(name_ch, 1, 10)

最後我只好改用 CONVERT 的方式來寫,如下:

CONVERT(VARCHAR(10), name_ch)

如果大家知道 SUBSTRING 有類似 DATALENGTH 的函式可以用的話麻煩通知我一下嘿!

2012年7月9日 星期一

如何在 Linq 裡面使用類似 SQL 的 IN 的語法?

需求是這樣的,使用者會輸入一個日期區間、並挑選業務員,
我在查詢的畫面會【列出所有的主檔資料】讓使用者勾選要列印哪一個主檔的資料,
但是當使用者按下一個【filter】的按鈕之後,
我會過濾出那個業務員有業績的資料,
然後取代剛剛那個【列出所有的主檔資料】的畫面讓使用者勾選。
以前的作法會大概會是過濾的時候順便 JOIN 主檔的資料,
然後列在主檔的畫面讓使用者勾選。

不過我在作的時候突然想到,我前端都已經有全部的主檔資料了,
為什麼還要再 JOIN 一次呢?
為什麼還要再增加那台五年前很強的主機的負擔呢?

所以我就想說有沒有辦法可以在前端作 JOIN 或是用 IN 的方式呢?
摸索了一下, Linq 沒有 IN 可以用,不過找到了另一個方式可以代替,
在我還沒有找到其他方式之前就先這麼辦吧!

測試的畫面大概長這樣!最左邊列出所有的產品,中間列出指定業務員有交易過的產品。


當業務員選擇 Frankie 的時候,則只列出 Frankie 有交易過的產品資料。
所以就不是全部的產品了!


選擇 Mork 的時候,顯示出有交易過的產品又更少了!


程式碼如下:
  1. string sales = leSales.EditValue.ToString();
  2.  
  3. DataTable filterList = DBUtility.GetDataFromDB("deal",
  4.     string.Format("SELECT DISTINCT product FROM deal WHERE sales = '{0}'", sales));
  5.  
  6. var q = filterList.AsEnumerable()
  7.     .Select(f => f.FieldByName("product").AsString);
  8. var filterResult = allProducts.AsEnumerable()
  9.     .Where(r => q.Contains(r.FieldByName("code").AsString));
  10.  
  11. DataTable filterProducts = null;
  12. if (filterResult.Count() > 0) filterProducts = filterResult.CopyToDataTable();
  13. grdFilter.DataSource = filterProducts;

這邊有用 DevExpress 的元件,所以有些物件的屬性不懂就跳過吧!

1.先取得業務員代號。

3.取得業務員曾交易過的產品代號。

6.將交易過的產品存到 q 裡面。

8.這個時候就可以用 q.Contains 當 SQL IN 來用了!

13.最後將過濾過的資料集塞回去 Grid 就可以了!


2012年6月15日 星期五

C# - 如何移除未知名稱的事件 - LookupEdit.KeyDown


之前寫過【C# 如何移除未知名稱的事件 - BarButtonItem.Click】,
然後剛好今天又要用到相關的觀念,
只不過今天要移除的是 LookupEdit.KeyDown ,
所以基本上這一篇只是紀錄一下,
萬一以後要用的時候可以直接拿來用這樣!

程式碼如下:

SQL SERVER - 修改資料庫邏輯名稱、移動資料庫檔案

雖然我不是處女座的,
但是我有習慣會想把相同的東西歸在同一個地方,
這樣以後找起東西來也比較好找。
資料庫的東西也是,基本上我都會放在 C:\DBFile 的資料夾下面,
不過有時候新增資料庫的時候會忘了改路徑;

程式開發的初期有時候無可避免的系統名稱改變了!(雖然是一樣的東西)
但是之前資料庫的名稱已經是用就名稱了,
以前想要改變的話大概只能備份下來之後再 restore 回去到新的資料庫,
不過今天突然覺得很懶,想說應該有比較直接的方式吧?
所以上網估狗了一下!語法大致如下:


--修改資料庫邏輯名稱
Alter DataBASE DB_NAME
MODIFY FILE(NAME= 'DB_NAME' ,NEWNAME= 'DB_NAME-BACKUP' )
Alter DataBASE DB_NAME
MODIFY FILE(NAME= 'DB_NAME_log', NEWNAME= 'DB_NAME-BACKUP_log' )

--查詢資料庫實體檔案位置
SELECT name, physical_name AS CurrentLocation, state_desc
FROM sys.master_files
WHERE database_id = DB_ID(N'DB_NAME');

ALTER DATABASE DB_NAME SET OFFLINE;

--OFFLINE 之後要手動複製實體檔案到想要的位置
--移動實體資料庫檔案
ALTER DATABASE DB_NAME
MODIFY FILE ( NAME = [DB_NAME-BACKUP], FILENAME = 'C:\DBFile\DB_NAME-BACKUP.mdf' );

ALTER DATABASE DB_NAME
MODIFY FILE ( NAME = [DB_NAME-BACKUP_log], FILENAME = 'C:\DBFile\DB_NAME-BACKUP_log.ldf' );

--必須先手動修改檔案的存取權限
ALTER DATABASE DB_NAME SET ONLINE;

--修改資料庫名稱
EXEC sp_rename 'DB_NAME', 'DB_NAME-BACKUP', 'DATABASE'

這樣大致OK了!進步始終來自惰性!

參考網址:移動使用者資料庫

2012年5月14日 星期一

C# - DataGridView 自動對應 DataTable 欄位

沒甚麼特別的,只是覺得測試的時候這個蠻好用的!所以分享一下!


public static void AdjustDataGridViewColumn(DataTable dataTable, DataGridView dataGridView)
{
    dataGridView.Columns.Clear();

    for (int i = 0; i < dataTable.Columns.Count; i++)
    {
        DataColumn dc = dataTable.Columns[i];

        DataGridViewTextBoxColumn col = new DataGridViewTextBoxColumn();
        col.Name = dc.ColumnName;
        col.ValueType = typeof(string);
        col.DataPropertyName = dc.ColumnName;
        col.HeaderText = dc.Caption;
        col.Visible = true;
        col.FillWeight = 150;
        dataGridView.Columns.Add(col);
    }
}


C# - DataGridView 控制項的資料行中至少有一行沒有儲存格樣板。


由於在測試一些東西,所以想要一個功能就是下完查詢之後,
DataGridView 可以自動調整成 DataTable 對應的欄位,
但是一直出現這個錯誤訊息!



後來我直接將 DataGridViewColumn 換成 DataGridViewTextBoxColumn 就沒有問題了!

這行不要!


DataGridViewColumn col = new DataGridViewColumn();


換成這行!


DataGridViewTextBoxColumn col = new DataGridViewTextBoxColumn();


C# - 如何得到 DataTable 某個字串欄位的最大長度?


總之我就是有一個需求,是要把 CSV 檔案直接存入資料庫的新資料表,
所以呢我必須要利用 CSV 檔案產生新的資料表,
大部份的欄位都是直接開 VARCHAR ,
產生新的資料表的這個部份可以用我上一篇講的 SMO 來處理,
但是有一個問題是,我欄位長度要設定多少?
當然我可以直接設定 VARCHAR(200) ,應該行的通,只是很 low ....
我也可以跑回圈找到最長的那一筆資料,不過也是個 low ....
然後我就看到 Linq 裡面有 Max() 可以使用,不過該怎麼用呢?
花了一點時間踹一下,果然可以用,感覺不那麼 low 了....


int max = DataTable. AsEnumerable().Max(r => r.Field<String>(colName).Length);


這樣是不是有高級一點點的感覺?

C# - 操作資料庫的利器 - SQL Server Management Objects (SMO)


前陣子因為要寫 Log 的相關功能,
所以需要程式可以自動產生 Log 的 Table ,
但是無奈 C# 並沒有內建相關的功能可以使用,
然後我又不想自己去解析 sys.object & sys.columns 相關的東西,
雖然已經解析過兩三次了,也有半成品可以使用,
但總是覺得這樣程式寫起來不漂亮,所以不想使用!
然後就一直搜尋是否有比較直覺的方式可以使用,
就在快放棄的時候讓我看到了一篇文章,
Getting started with SQL Server Management Objects (SMO)
裡面有介紹如何使用,我大致看了一下,
便覺得這就是我要找的東西丫!丫!丫!丫!
於是跟著做了一次,使用上果然直覺多了!
馬上就拿來應用在我的程式上了!
下面我就大概講一下如何使用吧!
首先妳的專案要先 reference 幾個東西,
跟文章裡面講得有點不一樣,因為他講的東西我有一樣找不到,

Microsoft.SqlServer.ConnectionInfo
Microsoft.SqlServer.Management.Sdk.Sfc
Microsoft.SqlServer.Smo
Microsoft.SqlServer.SmoExtended
Microsoft.SqlServer.SqlEnum

文章裡面有解釋各自是甚麼東西,做甚麼用的,請自行參考。

2012年5月4日 星期五

【Excel Data Reader】- OUT!!!


早上又看了另外一個元件【Excel Data Reader】
他網頁的標題是這樣的【Excel Data Reader - Read Excel files in .NET】
Project Description 上面寫有支援到 Excel 2007 ,
不過只到 .Net Framework 2 ?


2012年5月3日 星期四

掰伊~掰伊~~ LinqToExcel !!!


因為 NPOI 不支援 Excel 2007 所以我又跑回來試 LinqToExcel ,
利用 LINQPad 直接來測試,是說點下去沒有東西會出來實在是很難用丫!

anyway 我寫了一小段程式來測試,

void Main()
{
        var fileName = System.IO.Path.Combine(@"C:\ExportData", "data.CSV");
        var excelFile = new LinqToExcel.ExcelQueryFactory(fileName);     
        excelFile.DatabaseEngine = LinqToExcel.Domain.DatabaseEngine.Ace;

        var excel = excelFile.Worksheet<exl>();
        foreach (var element in excel)
        {
                element.Dump();
                "".Dump();
        }
}

// Define other methods and classes here
public class exl
{
        public string no { get; set; }
        public string name { get; set; }
        public string tel { get; set; }
        public string addr { get; set; }
}


重點在於我的電腦是 x64 的,
所以必須加上一行來指定 DatabaseEngine ,

excelFile.DatabaseEngine = LinqToExcel.Domain.DatabaseEngine.Ace

找了很久,也許是因為用 LINQPad 的關係,
因為網頁上的範例只寫了

excelFile.DatabaseEngine = DatabaseEngine.Ace

導致 LINQPad 一直有錯誤,說是 DatabaseEngine 沒有甚麼OOXX的....
搞了我好久,最後還是回到 VS2008 上面去才比較快找到原因,
最後終於可以跑出來了!

但是我還想試 LinqToExcel 一個功能,

    var excel = excelFile.Worksheet<exl>()
                .Where(d=>d.name=="Frankie");


沒想到這個時候又跳出了 OLE DB 的錯誤了!



找了半天, excel 沒有類似 DatabaseEngine 的屬性可以設定,
所以 LinqToExcel 就到此結束啦!枉費我這麼看好妳~~~


C# 讀寫 Excel 的另類選擇 - NPOI




這是一個不需要靠 OLE DB 或 COM 的方式可以直接讀寫 Excel 的元件,
可以參考這篇【在 Server 端存取 Excel 檔案的利器:NPOI Library】;
的確,當我們想把自動轉入資料的程式放在 Server 端的時候,
通常會遇到的問題就是 Server 沒有安裝 Excel !
這是一個多麼令人尷尬的事情丫!

那 NPOI 是甚麼東西呢?直接擷取網頁這一段來說明:


POI 專案本身是處理 Office 檔案的函式庫,包含 WordExcelPowerPointOutlookVisioPublisher 等檔案,這些檔案都有一個共通的特性,就是它們都是微軟發展的 OLE Compound Document(複合文件),以 OLE Structured Storage(結構化儲存)格式儲存在檔案中,OLE 規範(以及處理 OLE API 呼叫等)對一般的開發人員來說是有相當的難度,因此利用 Excel 本身的物件模型是最容易的一件事。但 POI 專案並沒有使用到 Excel 的任何東西,它直接深入 OLE Compound Document 格式內去存取資料,也可以直接控制到各種儲存格的資訊(顏色,儲存格格式與樣式等),並將它物件導向化,外部開發人員只需要利用 POI 提供的屬性就可以控制 Office 格式的檔案資料。


FileDialog.Filter 屬性怎麼寫


每次都忘記都要找,所以直接貼上來,
其實只是內建的說明而已 XD


Text files (*.txt)|*.txt|All files (*.*)|*.*
Image Files(*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.*
Excel files (*.xls)|*.xls|All files (*.*)|*.*

private void button1_Click(object sender, System.EventArgs e)
{
    Stream myStream = null;
    OpenFileDialog openFileDialog1 = new OpenFileDialog();

    openFileDialog1.InitialDirectory = "c:\\" ;
    openFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*" ;
    openFileDialog1.FilterIndex = 2 ;
    openFileDialog1.RestoreDirectory = true ;

    if(openFileDialog1.ShowDialog() == DialogResult.OK)
    {
        try
        {
            if ((myStream = openFileDialog1.OpenFile()) != null)
            {
                using (myStream)
                {
                    // Insert code to read the stream here.
                }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
        }
    }
}


2012年5月2日 星期三

LINQPad 使用 Linq 的好幫手

網路世界真是連來連去的,
因為找 NPOI 而找到 LinqToExcel ,
又因為 LinqToExcel 找到 LINQPad,
看了一下感覺不錯(又不錯!),所以馬上下載來用看看!
先看看這篇介紹吧!【LINQPad 有在用LINQ不可或缺的好工具

接下來開始使用囉!
也是因為我要踹 LinqToExcel 的關係啦!
先去官網 LINQPad 將 LINQPad download 下來吧!



看到那個標題真的有同感~~~哈哈!
有兩種程式可以下載,一種是要安裝的、一種是可以直接執行的!
我是先抓 Standalone Executable 來測試啦!

LinqToExcel

今天在找讀取 Excel 的相關東西,
簡單的說就是不要透過 OLE 跟 COM 來讀取,
原本找到一個 NPOI 的東西,
在找 NPOI 的相關資料的時候又找到了這個 LinqToExcel ,
看了一下別人的介紹【讀取 Excel 你還在用 NPOI 嗎?快來試試 LinqToExcel】,
感覺還蠻不錯的,決定就是它了!
所以馬上按圖索驥開始來試用它!

中間也試用了一下 LINQPad ,
不過在用的途中出現了一個訊息,
讓我不得不放棄它丫!



但是我不死心,我幻想其實是 LINQPad 的關係,
所以上了 LinqToExcel 網站查看看。



官網:linqtoexcel
Source code:https://github.com/paulyoder/LinqToExcel

因為跟我的需求的前提不符合,所以就只好放棄啦!
不然我覺得應該是不錯的東西才對!
有需要的人,然後又不反對用 OLEDB 的話可以試試看喔!



2012年4月30日 星期一

強迫寫入XtraGrid.RepositoryItem 的值到 DataRow 去

前幾天跟 XtraGrid 奮戰了好久,
或許應該要說跟 RepositoryItem 奮戰吧!
主要的原因是因為要讓 User 直接在 Grid 上面修改 Detail 的資料,
但是如果 User 修改完資料直接按下存檔,
Detail 上面最後一筆的修改並不會存入 DataTable;
原本我們在其他的 XtraEditor 的時候會去抓 DataBinding ,
然後強迫他寫入,如下:

Binding b = XtraEditors.DataBindings[0];
if (!(b == null)) b.WriteValue();

爸特~~~

2012年4月24日 星期二

並未將物件參考設定為物件的執行個體?


某天半夜,(沒錯!很悽慘的半夜!)
當我正在如火如荼的為了明天的 demo 趕程式的時候,
突然跳出了一個錯誤!



CurrentRow 是我在報表底層加的一個屬性,
用來回傳現在列印到哪一個 DataRow ,
結果現在沒辦法寫程式了,因為這個訊息會一直跳出來,
按掉了又馬上跳出來!只能直接用工作管理員把 VS 關掉...慘!
不過半夜趕程式中,腦袋不清不楚的,實在是一時想不出來為什麼會有問題丫!
明明我只寫了這樣

2012年3月20日 星期二

C# 見鬼了【這些資料目前沒有唯一的值】?


原本我寫了一段程式來產生一個 mapping 用的 DataTable,
程式碼如下:

DataTable mappingValue = SystemFuncs.GetTableByQuery(
    "SELECT key_, import_value_, mapping_value_ FROM import_mapping_item ");

DataColumn[] keys = new DataColumn[2]{mappingValue.Columns[0], mappingValue.Columns[1]};

mappingValue.PrimaryKey = keys;

某天突然就發生了錯誤,錯誤訊息如下:


2012年3月15日 星期四

SqlDataAdapter.UpdateBatchSize


今天客戶反應說匯入程式的效能不好,
他說匯入四千多筆資料要 3 分鐘左右,
個人是覺得四千多筆資料 3 分鐘應該是可以接受的範圍吧?
不過客戶說覺得不好也只能調整看看了!
客戶查了資料發現,其實資料寫入 Local 的 DataTable 其實花不到 3 秒鐘,
所以大部分的時間應該是卡在從 DataTable 寫入 DB 的時間,
個人是覺得這個我好像沒甚麼好調整的吧?
不過在我本機測試了一下,
發現不管我怎麼測,通通都沒有超過 1000 毫秒?
這樣表示其實也不是寫入 DB 的速度慢囉?
那麼是客戶端網路環境的關係嗎?

在無聊亂看的時候發現有 SqlDataAdapter.UpdateBatchSize 這個參數可以調整,
這個參數是來調整一次要一筆寫入還是整批寫入,
然後可以調整一批的數量的參數。
不過匯入程式是一次把四千多筆資料一次丟上去,
然後呼叫 SqlDataAdapter.Update 來寫入DB的,
這樣他不會一次一整批寫入嗎?
查了半天,沒找到哪邊有提到他的預設值是甚麼?
直接 Debug 看他的值才發現預設是 1 ㄟ
只怪我把世界想的太美好了!
查了一下 SqlDataAdapter.UpdateBatchSize 要怎麼用,
說明裡面有說:



將其設為大於 1 的值時,與 SqlDataAdapter 相關聯的所有命令都必須將其 UpdatedRowSource 屬性設為 None OutputParameters。否則會擲回例外狀況。


不過我照著寫

SqlDataAdapter.UpdateCommand.UpdatedRowSource = UpdateRowSource.None;



卻會有錯誤訊息!
所以我最後只有加寫了一行

SqlDataAdapter.UpdateBatchSize = 10000;



目前看起來單筆修改跟整批匯入的 Update 都沒有問題,
似乎是有比較快一點,接下來就看客戶那邊有沒有變快囉!

2012年2月7日 星期二

C# 如何移除未知名稱的事件 - BarButtonItem.Click


上次有寫過,
如果傳進來的 BindingSource 有 PositionChanged 的事件的時候就去觸發它!
請參閱【C# 如何強制驅動物件的事件?】。

這次不一樣的是,如果傳進來的 BarButtonItem 有 ItemClick 的事件的話,
我要將它移除,然後重新掛上自己的事件。
為什麼會有這樣的需求呢?
因為在底層的查詢按鈕直接將事件寫在 ItemClick 上面了,
而我想要拿這個按鈕來用卻又不想要執行底層的程式,
所以我需要將原來 delegate 的移除之後再重新掛上我的 ItemClick 程式。
緣由說明完畢啦!接下來就要實做了,
依照上次【C# 如何強制驅動物件的事件?】的做法居然得不到 FieldInfo !
google 了很久,後來在 DevExpress 的討論區裡面看到一個範例,
雖然是 VB 有點看不太懂,
後來我照著翻譯成 C# 之後也是可以跑的,
程式碼如下:

2012年1月30日 星期一

C# 擴充方法 - Extensions

因為有需要要把 DataTable 的資料倒出來到 csv 檔案裡面去,
想要有很簡易的使用方式,
於是乎就參考到了 擴充方法 (C# 程式設計手冊) ,
程式寫完之後我就可以直接用 DataTable.ExportCSV 來使用我新增的方法了!
如下圖所示:



可以直接這樣點出來是不是很棒!
那這樣的程式該怎麼寫呢?

2012年1月27日 星期五

C# Threading Finial

上一篇文章(C# Threading - 使用 WaitHandle)有提到
【主執行緒要等副執行緒查完之後才會更新介面上的資訊感覺很鳥】,
所以今天我要來改善這個問題,
基本上我想到的解法就是把原本查詢按鈕按下去裡面的程式改成另一個獨立的函式,
然後用副執行緒去呼叫,
所以原來的 btnThreadingQuery_Click 就變成下面這樣啦!

private void btnThreadingQuery_Click(object sender, EventArgs e)
{
    ThreadPool.QueueUserWorkItem(new WaitCallback(QueryMain));
}

原來裡面的程式就被我移到了 QueryMain() 去了,然後妳還記得嗎?
在第一篇文章(C# 多緒程式該怎麼寫? - Threading)的時候,
我曾經說過副執行緒不可以直接去處理 UI 相關的東西,
所以原本我們在裡面有去控制按鈕跟滑鼠游標也要依照第一篇的觀念去修改,
全部的修改內容如下:

2012年1月23日 星期一

C# Threading - 使用 WaitHandle

上一篇文章(C# 多緒程式該怎麼寫? - Threading)說到,
副執行緒還再跑的時候按鈕卻已經浮起來了,
然後總執行時間也不太對,
因為那個總執行時間並不包含副執行緒跑完的時間!
沒想到這麼快我就找到了解決的方法了!
誤打誤撞的找到了 WaitHandle 的範例,
於是就照著範例改了一下程式,
範例如下:
先宣告 WaitHandle 的陣列

    // Define an array with two AutoResetEvent WaitHandles.
    static WaitHandle[] waitHandles = new WaitHandle[]
    {
        new AutoResetEvent(false),
        new AutoResetEvent(false)
    };

然後使用方式如下:

ThreadPool.QueueUserWorkItem(new WaitCallback(DoTask),         
        waitHandles[0]);
ThreadPool.QueueUserWorkItem(new WaitCallback(DoTask), 
        waitHandles[1]);
WaitHandle.WaitAll(waitHandles);

然後在副執行緒的最後要補上一行,
將傳進來的 AutoResetEvent 呼叫 Set(),
範例上是這樣寫的,如下:

are.Set();

看起來好像不難,所以我就先照著改一下囉!

2012年1月19日 星期四

C# 多緒程式該怎麼寫? - Threading

之前為了需要寫了一個多緒的程式,
為了怕忘記,所以寫了一個簡單的程式來紀錄一下多緒的程式該怎麼寫,
這樣以後自己才有的參考。

簡單的說就是兩個按鈕,一個是單緒的查詢、一個是多緒的查詢,
兩個查詢的內容基本上是一樣的,先查詢一個筆數很多的資料表,
然後再查一個筆數比較少的資料表。

程式執行的畫面如下:


由於單緒的程式會等第一個查詢完了之後才查第二個資料表,
所以妳會發現第二個查詢的時間其實就等於全部查詢的時間;
但是如果是多緒的程式的話妳就會發現第二個查詢的筆數跟時間會比較快出來,
而全部的執行時間其實只有1毫秒,因為這個只是去呼叫程式的時間,
並不是全部查詢完之後的時間。
(突然發現毫秒的字錯了!!!)

先來看看單緒的程式的寫法吧!

C# 計算執行時間的物件 - CalcTime

為了計算執行時間方便使用,
所以寫了一個計算時間的物件,
沒甚麼特別的,所以直接分享程式碼吧!

CalcTime 物件的使用方式如下:
第一步,先建立物件:

CalcTime calcTime = new CalcTime();


第二步,程式執行完了直接呼叫 Duration(),會直接丟出執行的毫秒的字串。

calcTime.Duration();


如果需要重新計算的話,直接呼叫 Restart() 就會重設了,不需要重新建立 CalcTime 物件。

calcTime.Restart();


CalcTime 物件的程式碼如下:

public class CalcTime
{
    TimeSpan tsStart;
    public CalcTime()
    {
        tsStart = new TimeSpan(DateTime.Now.Ticks);
    }
   
    public void Restart()
    {
        tsStart = new TimeSpan(DateTime.Now.Ticks);
    }

    public string Duration()
    {
        TimeSpan tsEnd = new TimeSpan(DateTime.Now.Ticks);
        TimeSpan ts = tsStart.Subtract(tsEnd).Duration();
        return ts.Milliseconds.ToString() + "毫秒";           
    }
}