For general questions and discussions specific to the AbleCommerce GOLD ASP.Net shopping cart software.
-
jguengerich
- Commodore (COMO)
- Posts: 436
- Joined: Tue May 07, 2013 1:59 pm
Post
by jguengerich » Tue Oct 04, 2016 8:44 am
I am trying to use the new (to R12) ExtendedFields collection on an order. I have tried both of the following (in R12 SR1):
Code: Select all
oneOrder.ExtendedFields["MY_FIELD"] = "MY_VALUE";
oneOrder.Save(false, false);
Code: Select all
oneOrder.ExtendedFields.SetValueByField("MY_FIELD", "MY_VALUE");
oneOrder.Save(false, false);
and the value is not being saved. There's no error, but trying to retrieve the value later just returns and empty string. I'm assuming they should be saved in the CustomFields table? No records are added to it.
Jay
-
mazhar
- Master Yoda
- Posts: 5084
- Joined: Wed Jul 09, 2008 8:21 am
-
Contact:
Post
by mazhar » Wed Oct 05, 2016 12:36 am
I am able to reproduce the issue. It seems like order object is having difficulty saving the custom field data due to custom save implementations to trigger alerts. Custom field seems to be working for other objects like product. The only way to save custom fields with order object seems to be by not using custom save method overload.
Code: Select all
oneOrder.ExtendedFields.SetValueByField("MY_FIELD", "MY_VALUE");
((CommerceBuilder.DomainModel.Entity)oneOrder).Save();
This is't recommended way to save order though you can try it on some orders. It will simply save order state as it is but with custom fields also flushed into database.
Please make sure to test it with few test orders just to make sure this save call is not corrupting any calculated information since we just skipped Save(false, false) overload. I am going to report a new issue to track this in our logs.
-
jguengerich
- Commodore (COMO)
- Posts: 436
- Joined: Tue May 07, 2013 1:59 pm
Post
by jguengerich » Thu Oct 06, 2016 11:01 am
That workaround is probably OK, I can do the oneOrder.Save(false, false), then immediately after that do the cast to Entity and save. I'll post an update after I have a chance to do some testing.
Jay
-
jguengerich
- Commodore (COMO)
- Posts: 436
- Joined: Tue May 07, 2013 1:59 pm
Post
by jguengerich » Fri Oct 07, 2016 9:50 am
I can't get your suggestion to work. I have even tried switching to LoadForCriteria instead of using LINQ. Here is my code:
Code: Select all
ICriteria agedAuthCriteria = NHibernateHelper.CreateCriteria<Order>()
.CreateAlias("OrderStatus", "os", NHibernate.SqlCommand.JoinType.InnerJoin)
.Add(NHibernate.Criterion.Restrictions.Lt("PaymentStatusId", (byte)OrderPaymentStatus.Paid))
.Add(NHibernate.Criterion.Restrictions.Lt("os.OrderBy", invoicedStatus.OrderBy))
.Add(NHibernate.Criterion.Restrictions.Lt("OrderDate", DateTime.Now.AddDays(-5)));
IList<Order> heldOrders = OrderDataSource.LoadForCriteria(agedAuthCriteria);
foreach (Order oneOrder in heldOrders)
{
Payment lastPayment = oneOrder.Payments.LastPayment();
if (lastPayment.PaymentMethod.PaymentInstrumentType != PaymentInstrumentType.PurchaseOrder)
{
string myValue = oneOrder.ExtendedFields["MyField"];
if (myValue != "MyValue")
{
if (lastPayment.PaymentStatus == PaymentStatus.Authorized)
{
oneOrder.ExtendedFields["MyField"] = "MyValue";
oneOrder.Save(false, false);
Entity orderAsEntity = (CommerceBuilder.DomainModel.Entity)oneOrder;
orderAsEntity.Save();
}
}
}
}
If I put a breakpoint on the if statment in Entity.Save():
Code: Select all
public override void Save()
{
base.Save();
// MAKE SURE TO SAVE EXTENDED FIELDS IF LOADED
if (_extendedFields != null)
{
_extendedFields.Save();
}
}
_extendedFields is null, and if I step through, _extendedFields.Save() is not executed.
Jay
-
mazhar
- Master Yoda
- Posts: 5084
- Joined: Wed Jul 09, 2008 8:21 am
-
Contact:
Post
by mazhar » Tue Oct 11, 2016 5:50 am
I think it maybe the nhibernate proxy objects creating trouble. Try to unproxy objects before setting/accessing custom fields on them. Give a try to following and see if it makes any differeance.
Code: Select all
if (lastPayment.PaymentStatus == PaymentStatus.Authorized)
{
var acOrder = AbleContext.Current.Database.GetSession()
.GetSessionImplementation()
.PersistenceContext
.Unproxy(oneOrder) AS CommerceBuilder.Orders.Order;
acOrder .ExtendedFields["MyField"] = "MyValue";
acOrder .Save(false, false);
Entity orderAsEntity = (CommerceBuilder.DomainModel.Entity)acOrder;
orderAsEntity.Save();
}
-
jguengerich
- Commodore (COMO)
- Posts: 436
- Joined: Tue May 07, 2013 1:59 pm
Post
by jguengerich » Tue Oct 11, 2016 8:36 am
Thanks, that woks. I had tried "unproxying" before based on your suggestion in the other thread, but I did it after I had already added values to the ExtendedFields (I think that was the difference anyway; whatever it was I tried didn't work in any case). I did have to modify your code a little; I think you mixed VB ("AS ...") in with your C# code to cast the unproxied object back to an Order
.
Code: Select all
if (lastPayment.PaymentStatus == PaymentStatus.Authorized)
{
var acOrder = (CommerceBuilder.Orders.Order)AbleContext.Current.Database.GetSession().GetSessionImplementation().PersistenceContext.Unproxy(oneOrder);
acOrder .ExtendedFields["MyField"] = "MyValue";
acOrder .Save(false, false);
Entity orderAsEntity = (CommerceBuilder.DomainModel.Entity)acOrder;
orderAsEntity.Save();
}
Jay
-
jguengerich
- Commodore (COMO)
- Posts: 436
- Joined: Tue May 07, 2013 1:59 pm
Post
by jguengerich » Tue Oct 11, 2016 8:43 am
I noticed something else related to this: If an order is deleted (on admin/orders/default.aspx, select the order, choose Delete from the drop-down at the bottom, click GO), the related records are not removed from the ac_CustomFields table.
Jay
-
mazhar
- Master Yoda
- Posts: 5084
- Joined: Wed Jul 09, 2008 8:21 am
-
Contact:
Post
by mazhar » Wed Oct 12, 2016 3:11 am
Yeah that's intended and kept this way for improved performance. You should remove the fields before deleting the order.
-
jguengerich
- Commodore (COMO)
- Posts: 436
- Joined: Tue May 07, 2013 1:59 pm
Post
by jguengerich » Wed Oct 12, 2016 3:20 am
I can easily add code to do it, I just think if the Admin UI is going to provide a way to delete orders, it should have the code in there to delete the custom fields too. I guess it isn't real important because there aren't very many scenarios where you'd want to delete an order on a live site, but I think it ought to be included in the shipped admin pages just to keep things "tidy"
.
Jay
-
AbleMods
- Master Yoda
- Posts: 5170
- Joined: Wed Sep 26, 2007 5:47 am
- Location: Fort Myers, Florida USA
Post
by AbleMods » Wed Oct 12, 2016 4:39 am
mazhar wrote:Yeah that's intended and kept this way for improved performance. You should remove the fields before deleting the order.
I strongly disagree. The whole point of a relational database system is to maintain proper data relationships. Intentionally creating orphan records can open the door to all sorts of problems later.
It's faster to orphan catalog nodes for the same reason. Yet you do it properly. Why is CustomFields any different?
-
jmestep
- AbleCommerce Angel
- Posts: 8164
- Joined: Sun Feb 29, 2004 8:04 pm
- Location: Dayton, OH
-
Contact:
Post
by jmestep » Wed Oct 12, 2016 11:27 pm
I agree with Joe. It's a little incomprehensible that it was really intended to not delete the custom fields.
-
mazhar
- Master Yoda
- Posts: 5084
- Joined: Wed Jul 09, 2008 8:21 am
-
Contact:
Post
by mazhar » Fri Oct 14, 2016 2:16 am
Extended fields are using existing ac_CustomFields table and there are couple of scenarios due to which we choose not to cascade delete. First ac_CustomFields is a special table which doesn't have foreign keys defined which means you can not force delete using database cascades. The fact that any entity could have an extended field if we try to detect and delete any associated custom field we will be adding one extra delete statement per entity delete. Also not many merchants will be using extended fields so that mean we maybe trying to enforce consistency over an install which doesn't even use this feature. There were couple of ideas to have some admin report/interface to list any used/orphaned custom fields and let merchant decide about them. Another option was to have a new routine in maintenance to cleanup any abandoned fields. The issue with this approach was the fact that ac_CustomFields are already being used by merchants and not everyone is doing them the proper way/extended entities for example setting proper table names and entity ids. So we may have mistakenly removed some useful custom information saved through custom codes instead of using CustomFieldsManager. The safe option seemed to leave the custom fields if entity is dropped unless they are taken care of before deleting the entity itself. We will put more thought into it now that you people have given some reviews.
-
jmestep
- AbleCommerce Angel
- Posts: 8164
- Joined: Sun Feb 29, 2004 8:04 pm
- Location: Dayton, OH
-
Contact:
Post
by jmestep » Sat Oct 15, 2016 1:07 am
Not deleting the order-related custom fields was probably not a crucial when we couldn't delete orders. But it seems like since you have started using extended fields to make them easier to use and make them look more like they are an actual part of an order, it would be more important. I think a custom field for an order is what I have used the most. What about adding a customfield field into the order table, like you have basketitem and orderitem customfields?
Not to be cruel, but if a programmer is using the ac_customfields table for a way in which it was not designed, it seems like it should be a use-at-your-own-risk scenario. I have used a couple of fields in the past that had not been designed that way, thinking AC wasn't using them, then later on regretted it and had to change code. But it was my fault for "assuming".
-
jguengerich
- Commodore (COMO)
- Posts: 436
- Joined: Tue May 07, 2013 1:59 pm
Post
by jguengerich » Mon Oct 17, 2016 2:50 am
My opinion: It would be OK to have the Entity code delete the custom fields, just like it adds/updates them. That way, anything a developer would put in the table using a "fake" TableName and/or unused ForeignKeyId would remain, but nothing would be orphaned. There could be a prominent comment in the release notes about the change in behavior. There could even be a checkbox in the store config to enable/disable this behavior. I understand the point about it requiring an extra delete per Entity delete, perhaps there could be some testing to see if it makes a noticeable difference in performance. I was trying to think what the most common causes of deleting records is; I guess the user deleting items from a basket, or deleting a basket after an order is created? In a high-volume site, how noticeable would the extra deletes be in those scenarios?
Jay
-
AbleMods
- Master Yoda
- Posts: 5170
- Joined: Wed Sep 26, 2007 5:47 am
- Location: Fort Myers, Florida USA
Post
by AbleMods » Mon Oct 17, 2016 3:06 am
I don't think it should matter what sort of performance gain there is. It makes no sense to intentionally orphan data that will be completely unusable.
-
RickSilver
- Lieutenant (LT)
- Posts: 66
- Joined: Mon Jun 22, 2009 5:49 pm
Post
by RickSilver » Wed Aug 30, 2017 11:50 am
Are ExtendedFields working for Orders now?
Rick