【问题标题】:Best approach to bind a datagridview to database entity/ies将datagridview绑定到数据库实体的最佳方法
【发布时间】:2014-02-02 17:30:15
【问题描述】:

这种方法是现有数据绑定数据网格视图的最佳方法吗?

我见过很多人在绑定数据网格视图时遇到问题,经过大量工作后,我发现这是最好的方法。我希望它可以帮助其他人,并且有人可以添加改进。

第 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)在表单中创建 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 5) 对我来说很不清楚。您的方法的主要优点之一是将数据库模型与业务模型分离。您可以通过创建一个可以保存多个表的属性的类来做到这一点。但是你只查询一张表。我写这篇文章的原因是,当你想从几个表中获取数据但把它放在一个对象中时,你会希望在数据库服务器端做尽可能多的工作,所以当你的查询被执行时,它会获取数据所以您可以直接填充对象属性。
  • @Leron 请具体告诉我第 5 步中不清楚的地方。也许我可以更新它来帮助你。
  • del Rio 我只是分享想法,我不需要特别帮助。如上所述 - 如果最后您只查询一个表,如果您不查询,那么我看不到付出所有这些努力的好处,如果您不这样做,那么如何构建表达式树就更重要了工作在数据库中完成。另外 - 在 MVC 设计中具有这样的东西 - 控制器中的 My_DBModel DB_context = new My_DBModel(); 不是你想要的。我认为更好的是另一个项目来照顾您的数据访问。
  • @Leron 你能放或链接一些例子吗?
  • 稍后我会试着整理一下我的想法。现在我只想澄清一下,我并不是说你的方法行不通,或者会引起问题,我只是认为有些事情可以做得更好。如果您对我所说的内容感兴趣,请查看 Repository 模式、Unit Of Work 模式、一些依赖容器,例如 UnityNInject,并且您可能还想研究为什么使用 @987654331 @ 直接来自控制器不是 MVC 模式中的最佳方法。

标签: c# .net winforms entity-framework


【解决方案1】:

您可以使用 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;
    }
}

有什么问题可以告诉我

【讨论】:

  • 是的,它可以工作,但是如果你想在一个数据网格中混合两个实体怎么办?在我的情况下,我只需在 ObjectToShow 中添加(另一个实体的)实例并添加相应的公共属性。您也可以使用 get 方法来显示其他内容或以其他格式显示。
  • 创建您的 objectToShow,然后使用来自两个实体的值填充它,将每个创建的 objecttoshow 添加到列表中。然后将datagridview绑定到列表并循环遍历列以适当地格式化
  • 感谢大家的评论。这也是我的方法,创建对象。您只需按代码配置列。我喜欢从编辑器中执行此操作,以便您可以看到代码时间的变化。
【解决方案2】:

所以,为了更好地解释我的想法,我会写一个答案(因为它不会限制我的字符数)但我 想说明一下,我只添加关于如何使您的初始代码变得更好而不是必须如何改进的想法 完毕。 话虽如此,让我们进入主题。我将从Step 2) Create an object that represents a row in the datagridview. 开始 因为我认为这就是一切。您的数据库模型(每个表的表和列)有时会反映 您的业​​务模型,但有时在您的业务逻辑中,您需要使用来自 2 个或更多数据库表的信息,我认为 最常见的方法是您选择的方法 - 创建一个代表业务逻辑需求的新类。即使在这里你 提供了一些选项,例如使用匿名对象或 [NotMapped] 属性,但我会将这些留给真正喜欢的人 这些其他选项中的任何一个,因为我也会参加新课程。 我将跳过第 3 步和第 4 步,因为我认为我没有什么有价值的东西可以写,直接去Step 5) query the database。 我认为应该重新考虑的第一件事是您赋予每个ModelViewController 的责任。正如我所写 在我的一个 cmets 中,我认为拥有另一个专门处理数据访问的项目是迄今为止我发现的最佳方法。为什么我 更喜欢这种方法?嗯 - 首先,正如我所写,您的数据库模型很可能不会反映您的业务模型。让在你的项目中说你 有Model 文件夹,你把所有的实体和业务对象放在那里。这很令人困惑,即使你会发现一个相当小的应用程序 你自己有很多类,即使在某些时候你也很难分辨哪个类代表一个数据库表(实体)以及你 在您的业务逻辑中使用。几个月后,你之后的那个人,甚至你,更难发现这些事情。所以这是一个简单的 可以使您的代码更具可读性的东西,这本身就不是一个小成就。在阅读了有关如何解耦应用程序的更多信息之后 如果我们认为单独的数据访问项目确实是一个好方法,那么将获取该数据的逻辑放在这个项目中是很有意义的。 我喜欢这样做的方式(请记住,我没有太多经验,我在写这些东西时正在学习)是使用Repository 模式。你可以阅读很多 关于这种模式及其使用方式的不同,只是为了向您展示使用存储库而不是

My_DBModel DB_context = new My_DBModel();    
List<myDatabaseObject> myDatabaseObject_list = DB_context.myDatabaseObject.ToList();

假设您有两个实体 - UserOrder。你有一个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...

您还拥有UserRepositoryOrderRepository,它们都继承自GenericRepository,因此对于每个实体,您已经拥有所有基本方法 已实施,因此您不必每次想要执行DeleteUpdate 时都重复自己。为什么我不喜欢My_DBModel DB_context = new My_DBModel();? 好吧,假设您使用了某种方法,比如GetOrdersBySomething(),并且您通过查询数据库在代码中的多个位置使用了这种方法。如果会发生什么 有人决定编写一个存储过程,该过程将从现在开始返回此信息 - 您必须找到实际使用此方法的所有位置并更改逻辑。 假设几个月后您也必须使用来自 Web 服务的数据。每次更改都会迫使您在应用程序的不同位置重写相同的逻辑。但是如果你 使用存储库,您的OrdersRepository 中将只有GetOrdersBySomething(),并且每次您必须进行更改时,您只会在此处进行更改,而不会在其他任何地方进行。

另外,如果我正确理解了您的帖子,那么主题是关于能够从数据库中的多个表中收集数据并将其绑定为数据源。那么什么样的问题 这可能会导致。即使您正在处理相对少量的数据,如果您首先单独查询每个表,然后尝试在服务器端填充您的业务对象,这 可能会导致很大的性能问题。如果您必须使用 3 个表,每个表有 10 列,则总共有 30 列。如果您只需要其中的 15 个,那么您想要的是数据库服务器 做它的工作并以您需要的方式返回这些列,因此服务器端的工作尽可能少。这将我引向我指出的下一个主题——表达式树。我不会 写很多关于它们的内容,因为我认为我对它们没有深入的了解,但这里是关于主题http://msdn.microsoft.com/en-us/library/bb882637.aspx 的官方 msdn 页面,你在哪里 可以阅读更多关于什么是表达式树,它背后的想法是什么。当您了解表达式树到底是什么时,就会更清楚为什么我认为您的示例在哪里 您只查询一个表并不是最好的,因为当您执行适当的查询时,这种方法真的很出色。

【讨论】:

  • 感谢您向许多人介绍您的方法。我会记住的,它非常有用。
猜你喜欢
  • 2012-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-26
  • 2012-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多