Search code examples
c#winformsentity-frameworkdata-binding

Error trying to bind Datagridview with Entity Framework?


Model:

Code:

  public partial class frmCotizaciones : Form
{
    public frmCotizaciones()
    {
        InitializeComponent();
        using (var ctx = new AefesaEntities1())
        {
            dataGridView1.DataSource = ctx.Productos.ToList();
        }
    }
}

Error:

I'm new to Entity Framework, and I want to know how to use it, since I can see the advantages of using it. What I'm trying to do is simply bind the Productos dataset to the datagrid, but it throws that exception, I'd really appreciate your help.


Solution

  • The problem is that your Producto class has not only simple properties (string, int) but also navigation properties that point to other classes the producto is in relation.

    In this particular case the error shows that the producto has a list of DetalleCotizacione (whatever it is). The proxy class for the producto returned from EF has a lazy loaded property for this, which means that the property is not evaluated until some code asks for it.

    And now comes the tricky part. Your client code asks for a list

    ctx.Productos.ToList();
    

    The list will be populated with productos where all simple properties (string, int) are initialized and all lazy loaded properties are not.

    And then you dispose the data context.

    Now the data grid binder inspects (by reflection) your objects and find a lot of public properties, including these that are initialized (string, int) and these that are not - navigation properties. The grid creates columns for all your public properties and starts to populate rows. It then asks for values of all public fields of the producto and in case of navigation propeties - it fails because your context is already disposed (at the end of the using block).

    There are two workarounds:

    1. initialize the list of columns of your grid in an explicit way rather than relying on auto generation of columns. This way you could create columns for all properties that are not lazy loaded navigation properties.

    2. project your productos to whatever anonymous type you want thus making explicit loading of simple and navigation properties inside the block where context lives:

      using (var ctx = new AefesaEntities1())
      {
          dataGridView1.DataSource = ctx.Productos
              .Select( p => new { id = p.ID, whatever = p.Whatever, lazy = p.Lazy1, etc. }
              .ToList();
      }