[英]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.