bug version 2.0, command confirm takes several minutes using big databases

9 years ago
I was about to customize nop 2.0, working on sql 2008 r2 and windows 2008 r2.
I have used your script to convert my database and it worked perfectly.
For info, I have 18516 orders, 136992 order notes, 72279 addresses etc.

The web site seems to work until I try to checkout. On the last step, when I click confirm button, the web site does not respond and the process consumes a lot of processor.
So I used the debugger to localize the problem and this is what I can see:
In the class BaseEntity, the following code is called thousands of times.
        public override bool Equals(object obj)
            return Equals(obj as BaseEntity);

When you look at the details of calls, we find that the obj variable takes values that have nothing to do with the current order. For example I see through all address of my database!! it’s like if the full database was used during the process.

Using  stack call, I can see that the last procedure call before this problem starts was
Nop.Data.DLL!Nop.Data.EfRepository<Nop.Core.Domain.Orders.Order>.Insert (Nop.Core.Domain.Orders.Order entity = {Nop.Core.Domain.Orders.Order}) Ligne 35

Finally, I tried to let the process execute during few minutes, and it finished correctly with no errors in more than 4 minutes. So I think it's not visible on small databases...

To test this, start a checkout process with debug and stop just before clic on confirm.
Put a breakpoint on class EfRepository<T> ---- void Insert(T entity)
click confirm
Put a breakpoint on class BaseEntity ---- bool Equals(object obj)
continue debugging and watch obj variable

Does anybody have the same issue?
Thanks for your help
9 years ago
I found a part of the bug!
The problem apears only on addresses in the same coutry, not all the database.
1 - If you want to reproduce the bug on clean database : create a new user with address in the same country than your billing address

2 - temporary put this code in class BaseEntity, correct email with your email
        public override bool Equals(object obj)
            var c = obj as Nop.Core.Domain.Common.Address;
            if (c != null && c.Email != "[email protected]")
            return Equals(obj as BaseEntity);

3 - with debugger attached and with your account create an order and checkout

What you will see  : the code will stop on the address of the other user!!!!
So if you have all your customers in the same country (like me with france) they are all procesed and it can take veeeery long.

Here is the sql code generated by EF:

exec sp_executesql N'SELECT
[Extent1].[Id] AS [Id],
[Extent1].[FirstName] AS [FirstName],
[Extent1].[LastName] AS [LastName],
[Extent1].[Email] AS [Email],
[Extent1].[Company] AS [Company],
[Extent1].[CountryId] AS [CountryId],
[Extent1].[StateProvinceId] AS [StateProvinceId],
[Extent1].[City] AS [City],
[Extent1].[Address1] AS [Address1],
[Extent1].[Address2] AS [Address2],
[Extent1].[ZipPostalCode] AS [ZipPostalCode],
[Extent1].[PhoneNumber] AS [PhoneNumber],
[Extent1].[FaxNumber] AS [FaxNumber],
[Extent1].[CreatedOnUtc] AS [CreatedOnUtc],
[Extent2].[Id] AS [Id1],
[Extent3].[Id] AS [Id2]
FROM   [dbo].[Address] AS [Extent1]
LEFT OUTER JOIN [dbo].[Order] AS [Extent2] ON [Extent1].[Id] = [Extent2].[BillingAddressId]
LEFT OUTER JOIN [dbo].[Order] AS [Extent3] ON ([Extent3].[ShippingAddressId] IS NOT NULL) AND ([Extent1].[Id] = [Extent3].[ShippingAddressId])
WHERE [Extent1].[CountryId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1

you can see than WHERE statement is on CountryId, here is the bug, but I don't know why.

Help me please!
9 years ago
Also have a problem with QueuedEmail, they are also loaded...
9 years ago

We'll investigate this issue.

You also wrote about QueuedEmail.What exactly is wrong? There's a task (Nop.Services.Messages.QueuedMessagesSendTask) which periodically (each 60 seconds) loads not sent email (in order to send them). That's OK
9 years ago
it is a second problem at the same location.
In the same process I described below, I saw that thousands of calls were made on QueuedEMails objects, and not by the scheduler.
But I did not find the sql statement responsable of that.

This second issue can be temporary avoided if I truncate QueuedEMails table, but the first one is blocking!

thank you for your response (and sorry for my poor english)
9 years ago
You're absolutely right. I don't understand why Entity Framework tries to load all addresses from the same country (and the state also in the next SQL command). Most probably this issue is caused by 'Order' mapping class (Nop.Data.Mapping.Orders.OrderMap):

this.HasRequired(o => o.BillingAddress).WithOptional().Map(x => x.MapKey("BillingAddressId")).WillCascadeOnDelete(false);
            this.HasOptional(o => o.ShippingAddress).WithOptionalDependent().Map(x => x.MapKey("ShippingAddressId")).WillCascadeOnDelete(false);

It should work fine. I reported this issue to EF team. Let's wait their response.

UPDATE: I've just tested it with EF 4.2 BETA. The same behavior

UPDATE 2: Even simple insert of any new address during order placing causes this issue. I used the following right before inserting the order:
_addressService.InsertAddress(new Address()
                            FirstName = "g0",
                            LastName = "g0",
                            Email = "[email protected]",
                            CountryId = 1,
                            StateProvinceId = 0,
                            City = "g0",
                            Address1 = "g0",
                            ZipPostalCode = "g0",
                            PhoneNumber = "g0",
                            CreatedOnUtc = DateTime.UtcNow
9 years ago
Take a try with the nHibernate version.
9 years ago
The issue is fixed. Please see changeset http://nopcommerce.codeplex.com/SourceControl/changeset/changes/f1285e896f42
9 years ago
Thank you so much, I will try it today!
8 years ago

Now it's finally fixed. Have a look at changeset http://nopcommerce.codeplex.com/SourceControl/changeset/changes/6f95e6ed8462.