[英]Best approach to bind a datagridview to database entity/ies
這種方法是數據綁定數據視圖的最佳方法嗎?
我見過許多人在綁定datagridviews時遇到問題,經過大量工作后我發現這是最好的方法。 我希望它可以幫助其他人,有人可以添加改進。
步驟1)使用編輯器創建dataGridView及其列。
步驟2)創建一個表示datagridview中的行的對象。
此對象可以根據需要包含任意數量的數據庫實例。 這是一個有兩個對象的例子(datagridview中有兩列)
public class ObjectToShow
{
MyDatabaseObject myDatabaseObject = new MyDatabaseObject();
public ObjectToShow(MyDatabaseObject myDatabaseObject)
{
this.myDatabaseObject = myDatabaseObject;
}
public string Data1 //to asign to a datagridview column
{
get { return myDatabaseObject.data1; }
set { myDatabaseObject.data1 = value; NotifyPropertyChanged("Data1")}
}
public string Data2 //to asign to another datagridview column
{
get { return myDatabaseObject.data2; }
set { myDatabaseObject.data2 = value; NotifyPropertyChanged("Data2"); }
}
//This is to notify the changes made to the object directly and not from the control. This refreshes the datagridview.
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
步驟3)在Form中創建ObjectToshow的BindingList和bindingSource,如下所示
BindingList<ObjectToshow> ObjectToShow_list = new BindingList<ObjectToshow>();
BindingSource bindingSource = new BindingSource();
步驟4)以這種方式創建綁定
//if we don't put this, each public property in ObjectToshow will generate a new column in the datagridview
//I think it's best to create the columns from the editor.
dataGridView1.AutoGenerateColumns = false;
//database -> <- bindingList -> <- bindingSource -> <- datagridview <- user
bindingSource.DataSource = ObjectToShow_list;
dataGridView1.DataSource = bindingSource;
dataGridView1.Columns["Column_Data1"].DataPropertyName = "Data1";
dataGridView1.Columns["Column_Data2"].DataPropertyName = "Data2";
步驟5)查詢數據庫
//Example bringing all the data from a database table. This should be done in a controller class.
My_DBModel DB_context = new My_DBModel();
List<myDatabaseObject> myDatabaseObject_list = DB_context.myDatabaseObject.ToList();
//Clear de previous data
ObjectToShow_list.Clear();
//Add the queried elements to the bindingList
foreach (myDatabaseObject item in myDatabaseObject_list)
{
ObjectToshow objectToshow = new ObjectToshow(item);
ObjectToShow_list.Add(objectToshow);
}
步驟6)根據需要修改bindingList或datagridview中的數據。 然后是DB_context.saveChanges()。
要添加數據,請將其直接添加到DB_context.myDatabaseObject.Add(new ...)並再次查詢數據庫; 如果你想從datagridview添加它,我認為你必須處理事件並將其添加到上下文中。
這就是我所做的,它的工作原理,但我不確定這是不是最好的方法。 提前致謝。
所以,為了更好地解釋我的想法,我會寫一個答案(因為它不會限制我的字符數)但我想清楚地表明我只是添加了關於如何使你的初始代碼更好的想法而不是必須如何完成。 說完后讓我們進入主題。 我將從Step 2) Create an object that represents a row in the datagridview.
開始Step 2) Create an object that represents a row in the datagridview.
因為我認為這就是它的全部意義所在。 您的數據庫模型(每個表的表和列)有時會反映您的業務模型,但有時在您的業務邏輯中,您需要使用來自2個或更多數據庫表的信息,我認為最常見的方法是你選擇了 - 創建一個代表業務邏輯需求的新類。 即使在這里你給了一些選項,比如使用匿名對象或[NotMapped]
屬性,但我會把這些留給那些真正喜歡這些其他選項的人,因為我也會選擇新的類。 我將跳過第3步和第4步,因為我認為我沒有什么價值可以寫出來並直接進入Step 5) query the database
。 我認為應該重新考慮的第一件事是你給每個Model
, View
和Controller
的責任。 正如我在其中一篇評論中所寫,我認為另一個專門處理數據訪問的項目是我發現的最佳方法。 為什么我更喜歡這種方法? 好吧 - 首先,正如我所寫,您的數據庫模型很可能不會反映您的業務模型。 假設您的項目中有Model
文件夾,並且您將所有實體和業務對象放在那里。 令人困惑的是,即使是一個相當小的應用程序,你會發現自己有很多類,甚至在某些時候你也很難告訴哪個類代表數據庫表(實體)以及你在業務邏輯中使用哪個類。 幾個月之后,在你找到那些東西,甚至是你之后,這個男人會更加困難。 所以這是一個簡單的事情,可以使你的代碼更具可讀性,這本身並不是一個小成就。 如果我們確定一個單獨的數據訪問項目是一個好的方法,那么在更多關於如何解耦應用程序的閱讀之后,那么將邏輯用於獲取該項目中的數據是很有意義的。 我喜歡這樣做的方式(請記住,我沒有太多經驗,我正在學習,因為我正在編寫這些東西)是使用Repository
模式。 您可以閱讀很多關於此模式及其使用的不同方式,但只是為了向您展示使用存儲庫而不是使用存儲庫的優勢
My_DBModel DB_context = new My_DBModel();
List<myDatabaseObject> myDatabaseObject_list = DB_context.myDatabaseObject.ToList();
假設您有兩個實體 - User
和Order
。 你有一個GenericRepository
,它實現了你在操作數據時使用的基本方法:
public class GenericRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
internal MyDbContext context;
internal DbSet<TEntity> dbSet;
public GenericRepository(MyDbContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
public virtual IQueryable<TEntity> GetAll()
{
return dbSet;
}
public virtual IQueryable<TEntity> GetBy(Expression<Func<TEntity, bool>> predicate)
{
return dbSet.Where(predicate);
}
public virtual TEntity GetById(long id)
{
return dbSet.Find(id);
}
//And so on...
並且你還有UserRepository
和OrderRepository
,它們都從GenericRepository
繼承,所以你已經為每個實體實現了所有基本方法,所以你不必每次都想重復執行Delete
或Update
。為什么我不這樣做比如My_DBModel DB_context = new My_DBModel();
? 好吧,想象一下你使用了一些方法,讓我們說GetOrdersBySomething()
,你可以通過查詢數據庫在代碼中的幾個地方使用這個方法。 如果某人決定編寫一個從現在開始將返回此信息的存儲過程,將會發生什么 - 您必須找到實際使用此方法的所有位置並更改邏輯。 假設幾個月后您還必須使用來自Web服務的數據......每次更改都會強制您在應用程序的不同位置重寫相同的邏輯。 但是如果你使用存儲庫,你只需要在OrdersRepository
GetOrdersBySomething()
,每當你必須進行更改時,你只能在這里和其他任何地方進行更改。
此外,如果我正確理解您的帖子,主要的主題是能夠從數據庫中的幾個表中收集數據並將其綁定為數據源。 那么這可能導致什么樣的問題。 即使您處理的是相對少量的數據,如果您首先單獨查詢每個表,然后嘗試在服務器端填充業務對象,這可能會導致嚴重的性能問題。 如果你必須使用3個表,每個表10個列,總共30列。 如果你只需要其中的15個,那么你想要的就是數據庫服務器做它的工作並以你需要的方式返回那些列,所以服務器端的工作盡可能少。 這引出了我指出的下一個主題 - 表達樹。 我不會寫太多關於它們的原因我不認為我對它們有一些深刻的理解,但這里是關於該主題的官方msdn頁面http://msdn.microsoft.com/en-us/library/bb882637。 aspx ,你可以在這里閱讀更多關於表達式樹的內容,它背后的想法是什么。 當你了解到表達式樹究竟是什么時,那么我會更清楚地看到為什么你只針對一個表查詢的例子並不是最好的,因為當你執行適當的查詢時這種方法真的很棒。
您可以使用AutoGenerateColumns將DataGridView
綁定到DataSource
dataGridView1.DataSource = [yourDataSource]
然后遍歷列並在循環中設置它們的屬性,這將允許您隱藏您不想看到的列,名稱標題等。
這就是我的做法
foreach (DataGridViewColumn col in dgvReconciledItems.Columns)
{
switch (col.Name)
{
case "Column1":
col.HeaderText = "Header1";
col.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
col.FillWeight = 30;
break;
case "Column2":
col.HeaderText = "Header2";
col.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
col.FillWeight = 10;
break;
default:
col.Visible = false;
break;
}
}
有任何問題讓我知道
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.