Is there an issue binding a result to a DataGridView with combo boxes with NHibernate
I am having issues which I can't work out the issue to.
I am binding a DataGridView and creating my columns at run time. The text co开发者_JAVA技巧lumns work without issue, however I am having trouble with my drop downs, specifically I get a System.FormatException. I am binding a List<> to the datagridview which is retrieved from the database.
The data source for the grid view is structured like this:
- ProductID - Comments - Name - Brand : IBrand - Manufacturer : IBrandIBrand is structured like this:
- ID - NameWhen I create my columns, I use the following code:
DataGridViewComboBoxColumn column = new DataGridViewComboBoxColumn();
column.DisplayMember = "Name";
column.ValueMember = "ID";
column.DataPropertyName = "Manufacturer";
column.ValueType = typeof(IBrand);
column.DataSource = [List<> of IBrand], returned from NHibernate
Where am I going wrong? It's driving me nuts, it displays fine when I trap the Exception - but obviously, I don't want to trap the exception as there is an issue somewhere.
The only thing I can think of is that NHibernate is somehow causing issues here?
As eti pointed out, this definitely is a lazy loading problem. When you fetch your products and lazy loading is turned on (the default), you'll get all your products but only the id of the brand. When you then show a list of your products in the datagridview, nhibernate is trying to load the name of the brand. As you have closed the session object, it can't lazy load the brand entity, so you get an error back. I'd strongly suggest you take a look at ASP.Net MVC. It has a much cleaner model for working with ORMs (but yes, you lose all the fancy control binding). If you can't or don't want to, you have three options:
- disable lazy loading (very bad idea for performance reasons)
- you eager load the entities on an as needed basis when you do your querying (SetFetchMode("Brand", FetchMode.Join), NHibernateUtil.Initialize etc.)
- prepare a viewmodel object with all the entities eager loaded and send it to your aspx page.
I'm not sure if the answer below is directly tied to the Exception you are experiencing but i believe it will spare you a lot of trouble.
Short answer
You should not bind the objects returned by nhibernate to your UI. Project them to DTOs or ViewModel objects and bind those to the UI.
Long answer
NHibernate is an ORM designed to map your domain objects (the hole graph of interconnected objects that make up your business logic) to a relational database persistent storage. In order to be able to do this NHibernate uses lazy-loading to avoid loading all the graph of objects into memory. To perform lazy loading NHibernate uses generated proxies which are inherited from the from the class they proxy. Binding a proxy to the UI is not recommended because the proxy needs the ISession to still be active to be able to do lazy loading.
The Short Answer, yes is possible!!. I made a property in my Nhiberante model with only Get Property
public virtual Area Area { get; set; }
public virtual string Nome { get; set; }
public virtual string Descricao { get; set; }
public virtual bool IsActive { get; set; }
public virtual int Area_Id
{
get { return this.Area != null ? Area.Id : 0; }
}
My property Area_Id is a Calculate property and I´m not mapping this field in my FluentMapping.
public class CargoMapping : ClassMap<Cargo>
{
public CargoMapping()
{
this.Id(x => x.Id);
this.Map(x => x.Nome);
this.Map(x => x.Descricao);
this.Map(x => x.IsActive);
this.References(x => x.Area);
}
}
Then I call this Property for populate my ComboBox in DatagridView
DataGridViewComboBoxColumn dtgViewColumn = new DataGridViewComboBoxColumn();
dtgViewColumn.DataPropertyName = "Area_Id";
dtgViewColumn.HeaderText = "Area";
dtgViewColumn.Width = 120;
dtgViewColumn.DataSource = db.GetActive<Area>();
dtgViewColumn.ValueMember = "Id";
dtgViewColumn.DisplayMember = "Nome";
this.StarkDataGridView.Columns.Add(dtgViewColumn);
this.StarkDataGridView.ReadOnly = false;
this.StarkDataGridView.Columns["Id"].ReadOnly = true;
this.StarkDataGridView.AutoGenerateColumns = false;
this.StarkDataGridView.Columns["Id"].DisplayIndex = 0;
this.StarkDataGridView.Columns["Nome"].DisplayIndex = 1;
this.StarkDataGridView.Columns["Descricao"].DisplayIndex = 3;
this.StarkDataGridView.Columns["IsActive"].DisplayIndex = 4;
this.StarkDataGridView.Columns["IsActive"].HeaderCell.Value = "Ativo";
this.StarkDataGridView.Columns["Delete"].DisplayIndex = 5;
this.StarkDataGridView.Columns["Area"].Visible= false;
this.StarkDataGridView.Columns["Area_Id"].Visible = false;
I Hope that I help You!!
精彩评论