DataGridView exception when Delete an order via a Child form

Posts   
 
    
cgray
User
Posts: 62
Joined: 25-Nov-2007
# Posted on: 26-May-2008 22:59:19   

Hello, I am working through the tutorial "Rapid C# Windows Development.. & LLBLGen Pro" by Joseph Chancellor and ran into an exception when trying to delete via a child form. (End of Chapter 7, "Deleting an Entity".)

I realize that this tutorial was developed with an earlier version of .NET, so if this is an obscure problem, I'm willing to forget it and go on, completing the tutorial and then getting on to a real application.

However, if someone is familiar with this tutorial, or the problem is obvious, I'd appreciate suggestions.

Here is the exception, which happens at runtime:

The following exception occurred in the DataGridView:

System.Reflection.TargetInvocationException: Property accessor 'DueDate' on object 'AW.Data.EntityClasses.SalesOrderHeaderEntity' threw the following exception:'This entity is deleted from the database and can't be used in logic' -->

SD.LLBLGen.Pro.ORMsSUPPORTClasses.EntityBase.GetValue(Int32 fieldIntex, Boolean returnDefaultIfNull) at AW.DATA.EntityBaseClasses\SalesOrderHeaderEntityBase.cs:line1708 -- End of inner exception stack trace -- at System.ComponentModel.ReflectPropertyDescriptor.GetValue(Object component) at System.Windows.Forms.DataGridView.DataGridViewDataConnection.GetValue(Int32 boundColumnIndex, Int32 columnIndex, Int32 rowIndex)

To replace this default dialog please handle the DataError event.

I also get different property accessor errors, such as "Property accessor 'SalesOrderId' on object..

The environment: Runtime library version:

SD.LLBLGen.Pro.ORMSupportClasses.NET assembly version 2.5.0.0, file version 2.5.08.228

Database: Microsoft SQL Server 2005 Express Edition 9.0.1399, "AdventureWorks" Sample database

This is using Microsoft Visual Studio 2005, version 8.0.50727.42 and .NET Framework version 2.0.50727 SP1

I'm posting the source code below; please let me know if it would be better to include this as an attachment, or just include parts of the code.

Thanks for your assistance,

Carol

The source code for frmOrderEdit (see Delete method at the end):

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using AW.Data; using AW.Data.EntityClasses; using AW.Data.CollectionClasses; using AW.Data.HelperClasses; using SD.LLBLGen.Pro.ORMSupportClasses;

namespace AW.WIN { public partial class frmOrderEdit : Form { SalesOrderHeaderEntity _order; public frmOrderEdit() { InitializeComponent(); } public frmOrderEdit(SalesOrderHeaderEntity Order) { InitializeComponent(); _order = Order; }

    private void frmOrderEdit_Load(object sender, EventArgs e)
    {
        PopulateListBoxes();
        if (_order.IsNew == false)
        {
            PopulateOrderData();
            PopulateOrderDetailData();
        }

    }

    private void PopulateListBoxes()
    {
        cbShipMethod.DataSource = ShipMethodEntity.GetShipMethodCollection();
        cbShipMethod.DisplayMember = ShipMethodFieldIndex.Name.ToString();
        cbShipMethod.ValueMember = ShipMethodFieldIndex.ShipMethodId.ToString();
    }

    private void PopulateOrderData()
    {
        tbPurchaseOrder.Text = _order.PurchaseOrderNumber;
        tbSubtotal.Text = _order.SubTotal.ToString("N2");
        tbTax.Text = _order.TaxAmt.ToString("N2");
        tbFreight.Text = _order.Freight.ToString("N2");
        lblTotal.Text = _order.TotalDue.ToString("N2");
        tbContact.Text = _order.Contact.DisplayName;
        tbCustomer.Text = _order.CustomerViewRelated.DisplayName;
        cbOnlineOrder.Checked = _order.OnlineOrderFlag;
        dtpOrderDate.Value = _order.OrderDate;
        dtpDueDate.Value = _order.DueDate;
       if (_order.ShipDate != DateTime.MinValue)
            dtpShipDate.Value = _order.ShipDate.Value;
        else
            dtpShipDate.Checked = false;
        cbShipMethod.SelectedValue = _order.ShipMethodId;
    }

    private void PopulateOrderDetailData()
    {
        this.dgvDetails.DataSource = _order.SalesOrderDetail;
    }

    private void tsbSave_Click(object sender, EventArgs e)
    {
        if (SaveData())
        {
            this.Close();
        }
    }

    private bool SaveData()
    {
        try
        {
            _order.Freight = Convert.ToDecimal(tbFreight.Text);
            _order.PurchaseOrderNumber = tbPurchaseOrder.Text;
            _order.SubTotal = Convert.ToDecimal(tbSubtotal.Text);
            _order.TaxAmt = Convert.ToDecimal(tbTax.Text);
            _order.OnlineOrderFlag = cbOnlineOrder.Checked;
            _order.OrderDate = dtpOrderDate.Value;
            _order.DueDate = dtpDueDate.Value;
            if (dtpShipDate.Checked)
                _order.ShipDate = dtpShipDate.Value;
            else
                _order.SetNewFieldValue(
                    (int)SalesOrderHeaderFieldIndex.ShipDate, null);
            _order.ShipMethodId = Convert.ToInt32(cbShipMethod.SelectedValue);
            _order.Save();
            return true;
        }
        catch (Exception err)
        {
            MessageBox.Show(err.Message);
            return false;
        }       
    }

    private void tsbClose_Click(object sender, EventArgs e)
    {
        _order.Refetch();
        this.Close();
    }

    private void tsbDelete_Click(object sender, EventArgs e)
    {
        if (MessageBox.Show(
            "Are you sure you want to delete this order?", "Confirm delete", MessageBoxButtons.OKCancel,
            MessageBoxIcon.Warning) == DialogResult.OK)
        {
            _order.Delete();
            this.Close();           
        }
    }
}

}


The source code for the parent form, which launches the above form from a Toolstrip with Delete:

The relevant code:

private void dgvResults_CellContentDoubleClick(object sender, DataGridViewCellEventArgs e) { SalesOrderHeaderEntity Order = dgvResults.Rows[e.RowIndex].DataBoundItem as SalesOrderHeaderEntity; frmOrderEdit frm = new frmOrderEdit(Order); ((frmMain)this.MdiParent).LaunchChildForm(frm); }

The full code, with the relevant code above, about 5 methods from the bottom of this section:

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using AW.Data; using AW.Data.EntityClasses; using AW.Data.CollectionClasses; using AW.Data.HelperClasses; using SD.LLBLGen.Pro.ORMSupportClasses;

namespace AW.WIN { public partial class frmOrderSearch : Form { public frmOrderSearch() { InitializeComponent(); }

     private void btnSearch_Click(object sender, EventArgs e)
     {
         DateTime DateFrom = DateTime.MinValue;
         if (dtpDateFrom.Checked)
             DateFrom = dtpDateFrom.Value;
         DateTime DateTo = DateTime.MinValue;
         if (dtpDateTo.Checked)
             DateTo = dtpDateTo.Value;
         int OrderId = 0;
         string OrderNumber = "";
         if (tbOrderID.Text != "")
         {
             try
             {
                 OrderId = Convert.ToInt32(tbOrderID.Text);
             }
             catch
             {
                 OrderNumber = tbOrderID.Text;
             }
         }
         this.dgvResults.DataSource =
             SalesOrderHeaderEntity.GetSalesOrderHeaderCollection(
             DateFrom,
             DateTo,
             tbFirstName.Text,
             tbLastName.Text,
             OrderId,
             OrderNumber,
             tbCity.Text,
             cbState.Text,
             cbCountry.Text,
             tbZip.Text);
     }

     private void tableLayoutPanel1_Paint(object sender, PaintEventArgs e)
     {

     }

     private void dgvResults_CellContentDoubleClick(object sender, DataGridViewCellEventArgs e)
     {
         SalesOrderHeaderEntity Order =
             dgvResults.Rows[e.RowIndex].DataBoundItem 
             as SalesOrderHeaderEntity;
         frmOrderEdit frm = new frmOrderEdit(Order);
         ((frmMain)this.MdiParent).LaunchChildForm(frm);
     }

     private void tbFirstName_TextChanged(object sender, EventArgs e)
     {

     }

     private void frmOrderSearch_Load(object sender, EventArgs e)
     {
         this.cbCountry.DataSource =
             CountryRegionEntity.GetCountryRegionCollection();
         this.cbCountry.DisplayMember =
             CountryRegionFieldIndex.Name.ToString();
         this.cbCountry.ValueMember =
             CountryRegionFieldIndex.CountryRegionCode.ToString();
         this.cbCountry.Text = "";
         this.cbState.DataSource =
             StateProvinceEntity.GetStateProvinceCollection();
         this.cbState.DisplayMember =
             StateProvinceFieldIndex.Name.ToString();
         this.cbState.ValueMember =
             StateProvinceFieldIndex.StateProvinceId.ToString();
         this.cbState.Text = "";
     }

     private void newOrderToolStripMenuItem_Click(object sender, EventArgs e)
     {
         SalesOrderHeaderEntity Order = new SalesOrderHeaderEntity();
         Order.CustomerId = 17018;
         Order.ContactId = 4975;
         Order.BillToAddressId = 14810;
         Order.ShipToAddressId = 14810;
         frmOrderEdit frm = new frmOrderEdit(Order);
         ((frmMain)this.MdiParent).LaunchChildForm(frm);
     }

     private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
     {

     }
 }

}


And lastly, this is the custom code, added to SalesOrderHeaderEntity.cs, in the EntityClasses directory that was generated:

region Custom Entity code

    // __LLBLGENPRO_USER_CODE_REGION_START CustomEntityCode

    public string CustomerLastName
    { get { return this.CustomerViewRelated.LastName; } }

    public string CustomerFirstName
    { get { return this.CustomerViewRelated.FirstName; } }

    public string CustomerCity
    { get { return this.CustomerViewRelated.City; } }

    public string CustomerState
    { get { return this.CustomerViewRelated.StateProvinceName; } }

    public string CustomerCountry
    { get { return this.CustomerViewRelated.CountryRegionName; } }

    public string CustomerZip
    { get { return this.CustomerViewRelated.PostalCode; } }

    public static SalesOrderHeaderCollection GetSalesOrderHeaderCollection
    (
        DateTime FromDate,
        DateTime ToDate,
        string FirstName,
        string LastName,
        int OrderID,
        string OrderNumber,
        string CityName,
        string StateName,
        string CountryName,
        string Zip
     )
    {
        RelationCollection Relations = new RelationCollection();
        IPredicateExpression Filter = new PredicateExpression();
        if (
            (FirstName != "") |
            (LastName != "") |
            (CityName != "") |
            (StateName != "") |
            (CountryName != "") |
            (Zip != "")
        )
        {
            Relations.Add(
                SalesOrderHeaderEntity.Relations.
                CustomerViewRelatedEntityUsingCustomerId);
        }
        if (FromDate != DateTime.MinValue)
        {
            Filter.Add(
                SalesOrderHeaderFields.OrderDate >= FromDate);
        }
        if (ToDate != DateTime.MinValue)
        {
            Filter.Add(
                SalesOrderHeaderFields.OrderDate <= ToDate);
        }
        if (FirstName != "")
        {
            Filter.Add(
                CustomerViewRelatedFields.FirstName % FirstName);
        }
        if (LastName != "")
        {
            Filter.Add(
                CustomerViewRelatedFields.LastName % LastName);
        }
        if (CityName != "")
        {
            Filter.Add(
                CustomerViewRelatedFields.City % CityName);
        }
        if (StateName != "")
        {
            Filter.Add(
                CustomerViewRelatedFields.StateProvinceName == StateName);
        }
        if (CountryName != "")
        {
            Filter.Add(
                CustomerViewRelatedFields.CountryRegionName == CountryName);
        }
        if (Zip != "")
        {
            Filter.Add(
                CustomerViewRelatedFields.PostalCode == Zip);
        }

        if (OrderID != 0)
        {
            Filter.Add(
                SalesOrderHeaderFields.SalesOrderId == OrderID);
        }
        if (OrderNumber != "")
        {
            Filter.Add(
                SalesOrderHeaderFields.SalesOrderNumber == OrderNumber);
        }
        ISortExpression Sort = new SortExpression();
        Sort.Add(
            SalesOrderHeaderFields.OrderDate | SortOperator.Ascending);
        SalesOrderHeaderCollection Orders = new SalesOrderHeaderCollection();
 //  Orders.SupportsSorting = true; error SupportsSorting not found
        // add Prefetching
        IPrefetchPath Prefetch =
            new PrefetchPath((int)EntityType.SalesOrderHeaderEntity);
        Prefetch.Add(
            SalesOrderHeaderEntity.PrefetchPathCustomerViewRelated);
        Orders.GetMulti(Filter, 100, Sort, Relations, Prefetch);
//      Orders.GetMulti(Filter, 100, Sort, Relations);
        return Orders;
    }

    // __LLBLGENPRO_USER_CODE_REGION_END
Walaa avatar
Walaa
Support Team
Posts: 14994
Joined: 21-Aug-2005
# Posted on: 27-May-2008 08:42:47   

Would you please attach a repro solution mentioning the steps to reproduce the error?

cgray
User
Posts: 62
Joined: 25-Nov-2007
# Posted on: 29-May-2008 07:53:36   

Hello and thanks for your reply,

I have attached a zip file with the LLBL Gen data classes and the Windows application project (AW.Data and AW). This is a tutorial I've been going through, which uses the "AdventureWorks" (SQL Express, running locally) database provided by Microsoft. Please let me know if I should send that along as well.

In the future, I'll be using Oracle, so if the problem is related to the database, I'll be happy to ignore it and continue on.

What happens: When debugging, if you select "Order Search" Form and then double click on one of the lines in the GridView that is returned, it opens up the Child Form "Order Edit". This child form works for editing and saving data, but if delete is selected, after delete is confirmed, the exception happens and the only way to exit is by stopping debug in Visual Studio.

Thanks for your assistance, and please let me know if I should provide additional information or files.

Carol

Attachments
Filename File size Added on Approval
frmOrderEdit.Designer.cs 29,866 29-May-2008 07:57.29 Approved
cgray
User
Posts: 62
Joined: 25-Nov-2007
# Posted on: 29-May-2008 07:58:52   

Hi again, I just found that I was unable to upload a zip file, so am not sure how to proceed. I'm guessing you really don't want a bunch of separate files!

Thanks,

Carol

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 29-May-2008 08:25:13   

As you are using AdventureWorks, just made a repro-solution with the master and detail forms into. Upload without binaries, just the code. It should be no more than 5-6 files.

David Elizondo | LLBLGen Support Team
cgray
User
Posts: 62
Joined: 25-Nov-2007
# Posted on: 31-May-2008 21:49:40   

Hi again, I am using the AdvertureWorks database, running locally.

I finally have what I think are the relevant files, and will add attachments. There is a main MDI form (this is a Windows application), and several child forms. The child forms where the exception occurs are the Order Search and Order Edit forms. (I'm only attaching the .cs files, not the designer. Please let me know if I should include designer and resource files.)

In addition to the forms, several Entity classes were extended. Most of these were to enable code completion and such. The ones that seem the most important in this current exception problem (I think) are SalesOrderHeaderEntity.cs, which returns a collection, SalsOrderHeaderCollection; and CustomerViewRelatedEntity. I'll attach these two files as well.

Don't know if it is needed, but I'll include Program.cs, which launches frmMain.

As a quick recap, everything works fine except the Delete function (Delete button on frmEdit). When I select Delete, the program hangs and the exception occurs.

System.Reflection.TargetInvocationException: Property accessor 'DueDate' on object 'AW.Data.EntityClasses.SalesOrderHeaderEntity' threw the following exception:'This entity is deleted from the database and can't be used in logic' --> SD.LLBLGen.Pro.ORMsSUPPORTClasses.EntityBase.GetValue(Int32 fieldIntex, Boolean returnDefaultIfNull) at AW.DATA.EntityBaseClasses\SalesOrderHeaderEntityBase.cs:line1708 -- End of inner exception stack trace -- at System.ComponentModel.ReflectPropertyDescriptor.GetValue(Object component) at System.Windows.Forms.DataGridView.DataGridViewDataConnection.GetValue(Int32 boundColumnIndex, Int32 columnIndex, Int32 rowIndex)

Thanks for any suggestions, Carol

Attachments
Filename File size Added on Approval
frmMain.cs 1,950 31-May-2008 21:51.08 Approved
cgray
User
Posts: 62
Joined: 25-Nov-2007
# Posted on: 31-May-2008 21:52:07   

I only uploaded one file. Will now hit "continue" before upload and try and include the rest here. Carol

Attachments
Filename File size Added on Approval
frmOrderEdit.cs 4,161 31-May-2008 21:59.11 Approved
cgray
User
Posts: 62
Joined: 25-Nov-2007
# Posted on: 31-May-2008 22:02:39   

frm Edit attached

Attachments
Filename File size Added on Approval
frmOrderEdit.cs 4,161 31-May-2008 22:02.51 Approved
cgray
User
Posts: 62
Joined: 25-Nov-2007
# Posted on: 31-May-2008 22:11:29   

Since SalesOrderHeaderEntity.cs was too large to attach, here is a text file with the custom code, which I copied and pasted from the SalesOrderHeaderEntity.cs file.

Thanks, Carol

Attachments
Filename File size Added on Approval
custom_code_from_SalesOrderHeaderEntity.cs 4,282 31-May-2008 22:11.37 Approved
daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 02-Jun-2008 07:24:28   

I assume the error is this: you're editing (or simply showing in the grid) entities which were already deleted from the db. What you should do is remove entities from collection after you perform a delete operation.

Your problem is addressed here too: http://llblgen.com/TinyForum/Messages.aspx?ThreadID=7057

Anyway, I think you shouldn't start writing blindly the Book's code as some things have been changed from v2.0 to v2.5 (the book is written for v2.0). There are great examples for LLBLGen Pro v2.5 where you could start if you want.

I couldn't build your code as there are missing files. I you still have problems and want we have a look to your code, please:

  1. Create a copy of the folder where you have the solution (including LLBLGen Project [*.lgp]).
  2. Remove any binaries (bin/obj folders)
  3. ZIP the folder
  4. Attach the (one) zip file to your post.

Hope everything get well simple_smile

David Elizondo | LLBLGen Support Team
cgray
User
Posts: 62
Joined: 25-Nov-2007
# Posted on: 02-Jun-2008 19:14:44   

Hello, The thread you referred me to is the same issue I am having, that is, the bound collection has a deleted item and needs to be refreshed before it can be displayed properly. (I like that "go bezerk" term in the thread; it describes the situation quite nicely.)

The construct described in that question is very similar to what you're using: ask for a delete, if confirmed, proceed which then makes the grid go bezerk."

It it will be helpful for me to take a closer look at these comments. I'm guessing it will take a while to be able to master all this event handling with multiple forms!

Yesterday I went to the examples for LLBL Gen Pro v2.5 and downloaded the Validation examples. It is apparent that this has changed greatly in the last year or two. A quick, really basic question. To run the examples, you download the libraries and then create a separate project, which uses these classes, right? Or is there a "how to get started" section somewhere that I missed?

Thanks for your assistance, and the detailed instructions on getting a proper zip file. I was running into a problem with the file being too large, and will remove the binaries next time.

Carol

cgray
User
Posts: 62
Joined: 25-Nov-2007
# Posted on: 04-Jun-2008 20:00:02   

Hello, Well, I've just answered my own question. In looking more closely at the variety of examples provided, I see that there is at least one, "ASP.NET 2.0 databinding/CRUD Example", which has very detailed, step-by-step instructions in setting up a web project. I'll use this to revisit how to delete a record and then refresh a collection to update a grid properly. As it uses SelfServicing and is in C#, it looks like a good starting place. And several other examples apply directly to other functionality I hope to get working soon.

Thanks all,

Carol