Updateable BAQ


(Ken Nash) #1

I have an Updateable Dashboard. There is only one field that is updateable. Issue is when someone updates the record, while another user has the dashboard open. When user1 saves, their data is saved!! Then User2 makes changes and saves. User1 changes are overwritten by User2.

How do I prevent this? What are some ways you have gotten this to work.

Thanks,

Ken


Updateable Dashboard
(Jose C Gomez) #2

Put a Pre-Processing directive in the Update method of the UBAQ that compares Part.SysRev if they are different changes were made. Throw exception.


(Ken Nash) #3

I am going to assume I can do this for OrderRel as well. I am not seeing where the tt is being set and used in the update. It looks like the whole query ds is being processed.

Should I even care about the trace log? I see my change. But I also see the queryDS being sent with more records than I updated.

  <paramDataSet name="queryResultDataset" useDataSetNbr="0">
      <changedValue tableName="Results" rowState="Modified" rowNum="0" colName="OrderRel_Character02"><![CDATA[hi]]></changedValue>
    </paramDataSet>

Partial

  <paramDataSetChanges>
    <paramDataSet name="queryDS" useDataSetNbr="0">
      <changedValue tableName="QueryWhereItem" rowState="Added" rowNum="0" colName="Company"><![CDATA[EmbedTek]]></changedValue>
      <changedValue tableName="QueryWhereItem" rowState="Added" rowNum="0" colName="QueryID"><![CDATA[ETK_SchedShipments]]></changedValue>
      <changedValue tableName="QueryWhereItem" rowState="Added" rowNum="0" colName="SubQueryID"><![CDATA[f740c4f3-ed25-45ba-8373-340d4ac725b7]]></changedValue>
      <changedValue tableN....
  <changedValue tableName="QueryWhereItem" rowState="Added" rowNum="12" colName="ToTableID"><![CDATA[]]></changedValue>
  <changedValue tableName="QueryWhereItem" rowState="Added" rowNum="12" colName="ToFieldName"><![CDATA[]]></changedValue>
  <changedValue tableName="QueryWhereItem" rowState="Added" rowNum="12" colName="ToDataType"><![CDATA[]]></changedValue>
  <changedValue tableName="QueryWhereItem" rowState="Added" rowNum="12" colName="RValue"><![CDATA[_where-8587318048684276459]]></changedValue>
  <changedValue tableName="QueryWhereItem" rowState="Added" rowNum="12" colName="ExtSecurity"><![CDATA[False]]></changedValue>
  <changedValue tableName="QueryWhereItem" rowState="Added" rowNum="12" colName="SysRevID"><![CDATA[252276533]]></changedValue>
  <changedValue tableName="QueryWhereItem" rowState="Added" rowNum="12" colName="SysRowID"><![CDATA[d937b8f2-98a7-425b-8768-bc54a3cdcdfc]]></changedValue>
  <changedValue tableName="QueryWhereItem" rowState="Added" rowNum="12" colName="BitFlag"><![CDATA[0]]></changedValue>
  <changedValue tableName="QueryWhereItem" rowState="Added" rowNum="12" colName="RowMod"><![CDATA[]]></changedValue>
</paramDataSet>

(Jose C Gomez) #4

You lost me there Ken. The UBAQ’s work via BPMS (even the standard BO based ones generate a BPM behind the scenes).
If you click on Advanced BPM option int eh UBAQ Update Processing you can check if the ttResult.SysRevID == the SYsRevID on the Db.

and if they are NOT the same that means that the data has changed and you should abort the update.

(Ken Nash) #5

The BAQ is using BPM Update. Not Advance.

Wonder is that is part of the reason other fields are being updated.


(Jose C Gomez) #6

That’s fine click on that BPM Directives Configuration Button
you can still add a PreProcessing method to the Update (that Epicor Generates)


(Ken Nash) #7

ok closer.

Getting a type error on the following line. Is there a trick to do the compare?
if (ttResult.OrderRel_SysRevID == OrdRel.SysRevID)

Error CS0019: Operator ‘==’ cannot be applied to operands of type ‘long’ and ‘byte[]’

foreach (var ttResult in ttResults.Where(row => !string.IsNullOrEmpty(row.RowMod) && row.RowMod != "P").Select(row => row) )
{
			using (var txscope1 = IceDataContext.CreateDefaultTransactionScope())
			{
				
				var OrdRel = Db.OrderRel.Where(ordr=> ordr.Company == Constants.CurrentCompany
								&& ordr.OrderNum == ttResult.OrderNum
								&& ordr.OrderLine == ttResult.OrderLine
								&& ordr.OrderRelNum == ttResult.OrderRelNum
								).FirstOrDefault();
								
								
				if(OrdRel != null)

				{
				   if (ttResult.OrderRel_SysRevID == OrdRel.SysRevID)
				   {
							OrdRel["Character02"] = ttResult.OrderRel_Character02;
							OrdRel["Date01"] = ttResult.OrderRel_Date01;
							Db.Validate();
				   }
				   else
				   {
						var message = "This Record has been updated by another User.  Please Refresh Dashboard and make your change again.";

						throw new Ice.Common.BusinessObjectException(
						new Ice.Common.BusinessObjectMessage(message)
						{
						Type = Ice.Common.BusinessObjectMessageType.Error,
						});
				   }
				}

				
				txscope1.Complete();
			}
}

(Jose C Gomez) #8

You have to cast it to an int64 cause it’s a byte array. I’ll get you an example tomorrow


(Ken Nash) #9

thanks.

I just tried result = Convert.ToInt64(OrdRel.SysRevID); and that did not work.


(Jose C Gomez) #10

All right this was a giant pain in the ass LoL. Here is what you need to do
On the BAQ create a calculated field which will Cast the SysRevID to a BIG INT

Then on the BPM side Pre-Processing on Update get the current SysRevID and convert it also to a big int
Like this

var mycurrentRev = IPAddress.NetworkToHostOrder(BitConverter.ToInt64((from y in Db.OrderRel where y.SysRowID == x.OrderRel_SysRowID select y.SysRevID).FirstOrDefault(),0));

Note you will have to Click on Usings & References and add

using System.Net;

Then it is as simple as comparing the two values.

foreach(var x in ttResults.Where(r=>r.Updated()))
{
    var mycurrentRev = IPAddress.NetworkToHostOrder(BitConverter.ToInt64((from y in Db.OrderRel where y.SysRowID == x.OrderRel_SysRowID select y.SysRevID).FirstOrDefault(),0));
    if(x.Calculated_Calc_SysRevTT != mycurrentRev)
    {
        var message = "This Record has been updated by another User.  Please Refresh Dashboard and make your change again.";

        throw new Ice.Common.BusinessObjectException(
        new Ice.Common.BusinessObjectMessage(message)
        {
        Type = Ice.Common.BusinessObjectMessageType.Error,
        });
    }
}

Note do not do the actual updating here, let EPicor do the update in their “EpiMagical” base method. Your job is only in Pre-Processing to stop / raise an error if needed. Otherwise do nothing.


(Ken Nash) #11

ok I will try this out.

I think my other issue of data being saved is due to how the updateable BAQ is configured. That might be my next issue to investigate.

first need to solve this one.


(Erik Johnson) #12

Just in case it matters, a bigint in SQL server is a signed integer and the rowversion (SysRevID) value is an 8-byte array. SQL will cast it to a bigint, but if the SysRevID is high enough, the result will get flipped to a negative value, which a problem if you want to sort on the result.

In C#, you can convert the raw SysRevID value to a UInt64 (or unsigned long) like this:

UInt64 revId = BitConverter.ToUInt64(OrdRel.SysRevID.Reverse().ToArray(), 0);