BindingSource物件

八月 15, 2008 作者:mrmu  
類別: .Net Framework

BindingSource 元件有兩個用途。第一,它會在表單上的控制項繫結至資料時,提供間接取值 (Indirection) 層。這項作業的完成,是透過將 BindingSource 元件繫結至資料來源,然後將表單上的控制項繫結至 BindingSource 元件。所有與資料的進一步互動 (包括巡覽、排序、篩選和更新) 都會透過呼叫 BindingSource 元件來完成。

雖然 BindingNavigator 控制項是特別設計用來與 BindingSource 元件搭配使用的,不過還是可以使用 BindingSource 元件將任何 Windows Form 控制項繫結至資料來源,如ComboBox跟DataGridView,繫結至某資料表的BindingSource後,其內容就會是該資料表的記錄。DataGridView元件的欄位(Cell),也可以表示為控制項(如ComboBoxCell, TextBoxCell等),這些控制項也可以使用DataSource成員來做Binding。

根據預設,BindingNavigator 控制項所提供的按鈕是對應到 BindingSource 元件上的巡覽方法。

跟TableAdapter一樣,透過精靈操作時,若我們直接將資料表拉入表單(Form),它會自動加入元件至表單,並做好Binding動作(每個資料表都會有一個BindingSource物件),不管是使用「詳細資料」或「DataGridView」的方式皆會產生BindingSource物件。

BindingSource的類別成員 (msdn)

相關文章

TableAdapter

八月 1, 2008 作者:mrmu  
類別: .Net Framework

TableAdapter 提供應用程式與資料庫之間的通訊。TableAdapter 會連接到資料庫、執行查詢或預存程序,然後傳回一個已填入傳回之資料的新資料表,或是將傳回之資料填入現有的 DataTable (DataSet裝著一堆DataTable)。TableAdapter 也可用來將應用程式中更新的資料傳回到資料庫。

透過精靈的操作,vb.net會自動做一些事,大概是這樣的:

1. 新增資料來源 自動建立DataSet,它含有部份原始DB其中一部份的資料表(看你選了哪些資料表進來) 

2. 當我們將資料表拉入表單(Form)時 不管是用「詳細資料」的方式還是DataGridView,vb.net都會自動為該資料表做一個TableAdapter (一般會在Form_Load先幫你作Fill的預設動作,把全部資料查詢出來),除了生出TableAdapter,還會建立對應控制項的BindingSource物件。

相關文章

並行違規

七月 13, 2008 作者:mrmu  
類別: .Net Framework

接續上篇的練習,在新增一筆記錄後按”更新”按鈕,記錄的確會被寫回資料庫,但隨即刪除這筆記錄後再按”更新”,另一個錯誤就可能出現了:

對於初次見到這個訊息的我而言,我只能感覺到設計這行字的工程師真是天才,試問誰能一眼就了解這是錯在哪呢…

並行違規的問題似乎是因為第一個存取記錄的人把資料取回應用程式後,在要寫回資料庫時,由於第二個人已改變記錄了,因此造成二個以上的人同時編輯記錄,結果產生並行違規。在這個範例中,第二個人就是你自己。

簡單的解決方式是針對此情況對使用者發出提示,可以使用DBConcurrencyException來得知並行違規的問題發生了(處理並行存取錯誤的說明),確定要寫入就再做一次Fill及AcceptChanges(),不過最適當的方式還是要視專案情況(不同的商業邏輯)來解決:

相關文章

The DELETE statement conflicted with the REFERENCE constraint

七月 12, 2008 作者:mrmu  
類別: .Net Framework

這是在練習VB.net更新DataSet時遇到的第一個錯誤訊息。

練習更新DataSet時,做出了一個如下圖這樣的表單(一個label, 一個comboBox, 一個button, 兩個DataGridView):


以NORTHWIND範例資料庫為例,新增Products, Suppliers, Order Details資料表作為資料來源(如右圖)。

Products資料表階層下之所以還有個Order Details的資料表,主要是因為兩者之間有關聯(以ProductsID作關聯),Products為父資料表,Order Details為子資料表。同樣的,Suppliers與Products之間也有如此關聯(以SupplierID作關聯)。三個資料表之間的關聯如下圖。

這個簡單的例子要讓User能直接對DataGridView進行新增、刪除、修改後,在表單上提供一個”更新”按鈕讓User完成修改後可以將記錄寫回至資料庫。在放好Label, comboBox (DataSource屬性設為Suppliers資料表, DislayMember為Company Name,ValueMember為SupplierID)後,接著直接將資料來源視窗內的Suppliers資料表階層下的Products資料表拉進表單,成為表單中間的DataGridView;同樣的,Products下面的Order Details拉進,為下面的DataGridView。

更新按鈕的Click事件函數如下(為求簡單,先不考慮異常例外的處理):

Private Sub BtnUpdate_Click(ByVal sender As System.Object,_
           ByVal e As System.EventArgs) Handles BtnUpdate.Click
    Dim dsChanged As DataSet
    dsChanged = NORTHWNDDataSet.GetChanges(DataRowState.Added +_
                                          DataRowState.Deleted +_
                                          DataRowState.Modified)
    ProductsTableAdapter.Update(dsChanged)
End Sub

執行的畫面如下:

此時刪除Products記錄,可能會出現如下錯誤訊息:

這樣看來是容易理解的,因為NORTHWIND在Products與Order Details資料表存在Foreign Key(外來鍵),若刪除某個Product,該ID必須沒有與其他資料表有關聯,否則此關聯就被破壞了。例如,若把ID為38的產品刪除了,那所有訂單中有訂購ID為38的產品都將關聯不到ID為38的產品。解決方法可能就必須先刪除Order Details所有有訂購ID為38的產品之記錄,不過完整正確的作法當然要提示User,也要對有訂38的訂單記錄作適當的處理。

相關文章

Design Pattern: Factory Pattern (下)

十二月 11, 2007 作者:mrmu  
類別: Design Patterns

上回介紹到腳踏車行終於得到了工廠(Factory)來處理製造方面的部份,那麼究竟還有什麼樣的問題呢?
目前只有一個工廠,當產品種類愈來愈多時,簡易工廠的方式一樣是難以管理的;或許可以建立多個工廠來分類處理不同的產品,聽來是個不錯的主意。首先就讓工廠成為抽象/虛擬類別(abtract/virtual class),定義出它通用的成員以供繼承。在此,腳踏車行的功能較少,我們可以將工廠的功能與之結合。
// 當出現更多種類的Factory,且各個Factory都想發展獨特的製造方式
// 建立一個BicycleStore的抽象類別

public abstract class BicycleStore
{
public Bicycle orderBicycle(String type)
{
Bicycle oneBicycle;
oneBicycle = createBicycle(type);
oneBicycle.test();
oneBicycle.pack();
return oneBicycle;
}

abstract createBicycle(String type); //Factory method
}

// 一家BicycleStore的instance (新的Factory)
public class GiantBicycleStore extends BicycleStore
{
Bicycle createBicycle(String item) //Factory method (unique!)
{
if (item.equals(mountain))
{
return new MountainBicycle();
}
else if (item.equals(lady))
{
return new LadyBicycle();
}
else
{
return null;
}
}
}

另外在腳踏車部份,我們也有了抽象類別以供繼承:

//Bicycle的抽象類別
public abstract class Bicycle
{
String ID;
String Handle;
String Tire;
void test();
void pack();
void getID();
void setID();
}

//一種Bicycle的instance
public class MountainBicycle extends Bicycle
{
ID = MB123;
Handle = BendHandle;
Tire = Goodyeers;
void test()
{
//unique test way for MB123;
}
}

如此的構造,便可稱之為Factory Pattern。

相關文章

DesignPattern: Factory Pattern (上)

十二月 10, 2007 作者:mrmu  
類別: Design Patterns

最近有機會參與到Framework的設計與發展,於是開始trace一些open source的project,而SmartWin++即是首先觀察的對象。

一開始鑽進去看source code,發現它是template的重度使用者,很多高級用法尚未理解,索性先畫UML,看看它的長相。局部畫出它在元件(widget)方面的設計後,才發現,耶~「WidgetFactory」,這不是有名的Pattern嗎?又能有機會研究Design Pattern了。

昨天騎車上班時被撞,跑了兩家腳踏車行,所以就拿腳踏車來作為例子說明吧。(可惜服務態度都不好,騎腳踏車的人已經不多了,請好好珍惜顧客吧!)

開始製造腳踏車吧,一開始大概是這樣的:

Bicycle orderBicycle()
{
//製造
Bicycle oneBicycle = new Bicycle();

oneBicycle.test();
oneBicycle.pack();

return oneBicycle;
}

Order一台腳踏車,然後就被製造出來了。不過腳踏車可是有很多種類的,這種製造方法似乎還不夠。那麼這樣呢:

Bicycle orderBicycle(String type)
{
Bicycle oneBicycle;

if (type.equals(mountain))
{
oneBicycle = new MountainBicycle();
}
else if (type.equals(lady))
{
oneBicycle = new LadyBicycle();
}
else if (type.equals(child))
{
oneBicycle = new ChildBicycle();
}

oneBicycle.test();
oneBicycle.pack();

return oneBicycle;
}

哦! 看起來還不錯嘛!
不過這個世界是無常的,隨著時光飛逝,「少子化」的現象發燒,有天老闆決定小孩車不敷成本,不再生產了。反而著重在銀髮族群,於是可能會有這樣的改變:

Bicycle orderBicycle(String type)
{
Bicycle oneBicycle;

// 製造
if (type.equals(mountain))
{
oneBicycle = new MountainBicycle();
}
else if (type.equals(lady))
{
oneBicycle = new LadyBicycle();
}
// else if (type.equals(”child”)) // no more child bicycle!
// {
// oneBicycle = new ChildBicycle();
//}
else if (type.equals(oldman)) // new old man bicycle.
{
oneBicycle = new OldManBicycle();
}

oneBicycle.test();
oneBicycle.pack();

return oneBicycle;
}

呼~~費了一番工夫,調整了製造方式,什麼!? 又有新款車? 什麼!? XX車又不要了…
可以想像的到,日後只要新增車款或變更,你就要進來攪拌這盤 “義大利麵” 了… 好吧,我知道這些常常要改變的code,應該要分開來管理。有個比較聰明的作法,就是把它切出去 (也許請個誰來管理它吧)。
因為切出去的部份就是負責”製造”的部份,所以我們給它一個比較專業的名字-工廠 (Factory)。
來! 物件導向的設計呼之欲出:

//製造工廠
public class BicycleFactory
{
public Bicycle createBicycle (String type)
{
Bicycle oneBicycle = null;

if (type.equals(mountain))
{
oneBicycle = new MountainBicycle();
}
else if (type.equals(lady))
{
oneBicycle = new LadyBicycle();
}
// else if (type.equals(”child”)) // no more child bicycle!
// {
// oneBicycle = new ChildBicycle();
//}
else if (type.equals(oldman)) // new old man bicycle.
{
oneBicycle = new OldManBicycle();
}

return oneBicycle;
}
}

想像一下原來的orderBicycle(),應該是屬於腳踏車行提供的,所以我們也可以建立一個BicycleStore的Class:

public class BicycleStore
{
BicycleFactory oneFactory;

public BicycleStore (BicycleFactory factory)
{
this.oneFactory = factory;
}

public Bicycle orderBicycle(String type)
{
Bicycle oneBicycle;
oneBicycle = oneFactory.createBicycle(type);
oneBicycle.test();
oneBicycle.pack();
return oneBicycle;
}
}

故事發展至此,我們的”腳踏車行”得到了一個簡單的”工廠”,但這還不是真正的Factory Pattern呢,詳情下回分解。

相關文章