How to assign Data Tags in Custom Code

hello all,

I am trying to assign Data Tags to parts within a Function via custom code. The idea is to schedule this function to run however often, and I can later query the parts in a BAQ based on whether they have the “archive” tag. The query below is just the start of a much more complicated query, but does anyone know how to actually assign the tag?

var query = from part in Db.Part.Where(p => p.InActive == false)
            select new { part };
    
        
foreach(var p in query)
{
  if(p.part.RunOut == false && p.part.OnHold == false)
  {
    // add Data Tag
    Ice.BO.SysTagDataSet ds = new Ice.BO.SysTagDataSet();
    this.CallService<Ice.Proxy.BO.SysTagImpl>(ts => ts.GetNewSysTag(ds));
    
    foreach(var tag in ds.SysTag)
    {
       //this.CallService<Ice.Proxy.BO.SysTagImpl>(ts => ts.Update(ds));
    }
    
  }
}

I’m not sure if I should be using Ice.BO.SysTagDataSet, or a “tableset” which I’ve seen in other places, but that is what’s called in the trace file.

<tracePacket>
  <businessObject>Ice.Proxy.BO.SysTagImpl</businessObject>
  <methodName>GetNewSysTag</methodName>
...
  <parameters>
    <parameter name="ds" type="Ice.BO.SysTagDataSet">
      <SysTagDataSet xmlns="http://www.epicor.com/Ice/300/BO/SysTag/SysTag" />
    </parameter>
  </parameters>
</tracePacket>

This is all I can see from the intellisense.
image

Any help would be greatly appreciated!

Un momento

  CallService<SysTagSvcContract>(st =>
  {
    SysTagTableset stTS = new SysTagTableset();
    
    SysTagRow newTag = new SysTagRow()
    {
        Company          = CompanyID,
        ForeignSysRowID  = foreignSysRowID,
        ForeignTableName = foreignTableName,
        Tag              = tag,
        CreatedOn        = DateTime.Now,
        CreatedBy        = createdBy,
        IsShared         = shared,
        RowMod           = "A"
    };
    
    stTS.SysTag.Add(newTag);
    
    st.Update(ref stTS);
  
  });

Function Signature

Input →

Name Type
foreignTableName System.String
foreignSysRowID System.Guid
tag System.String
createdBy System.String
shared System.Boolean
2 Likes

Colin Farrell Actors GIF by PBS SoCal

1 Like

You’re amazing, thank you! I’m assuming it’ll work for me too, but will let you know if I bump into any issues.

1 Like

Hey Kevin,
Everything works up until the Update method.

var query = from part in Db.Part
            where part.PartNum == "F4780"
            select new { part };
    

foreach(var p in query)
{
  // add Data Tag
    
  //Ice.BO.SysTagDataSet ds = new Ice.BO.SysTagDataSet();
  //this.CallService<Ice.Proxy.BO.SysTagImpl>(ts => ts.GetNewSysTag(ds));
  //this.CallService<Ice.Proxy.BO.SysTagImpl>(ts => ts.Update(ds));
    
  CallService<SysTagSvcContract>(st => 
  {
    SysTagTableset stTS = new SysTagTableset();
    
    SysTagRow newTag = new SysTagRow()
    {
       Company = "TEI",
       ForeignSysRowID = p.part.SysRowID,
       ForeignTableName = "Part",
       Tag = "ArchiveCandidate",
       CreatedOn = DateTime.Now,
       CreatedBy = "JPoston",
       IsShared = true,
       RowMod = "A"
    };
    
    stTS.SysTag.Add(newTag);
    st.Update(ref stTS);
    
  });
    
} 

But I get this exception when I include the Update method.

Where would you go from here, or what should I be looking into next to figure out what’s wrong? This was run from the “Schedule Epicor Function” menu item.

I assume you are running this in a loop?

Try checking Requires Transaction on your function.

image

I’m speechless… Thank you, that fixed it, and everything is working now. I really don’t know how you guys learn all this stuff. The Field Help for that checkbox doesn’t provide any information on what its for. Maybe it does in a later version. But I can’t thank you enough. Thanks again!

Bad Santa Pain GIF by Sky

2 Likes

Just FYI, if you’re looping through things and need a transaction, and there’s a chance a that an iteration will fail, create a TransactionScope for each loop instead of just using the “use Transaction” checkbox.

Checking the box on the function will revert all changes if even one loop fails. Something like the code below will continue on to the next iteration while recording what failed.

Note that you do not check the Transaction box AND create a txScope in your code. One or the other.

foreach(var thing in things)
{
    try //So the whole thing doesn't die on a single error.
    {
        using (var txScope = IceContext.CreateDefaultTransactionScope())
        //Creates a Transaction for just this one iteration.
        {
            MethodCall();
            AnotherCall();
            txScope.Complete(); //Close out transaction
        }
    }
    catch (Exception e)
    { 
        ErrMsg += SomeKeyField + ":" + e.Message + Environment.NewLine;
        //ErrMsg would be an output on your function.
        //You could log any number of ways too.
        //This was just what I used on the code I copied this from, which was a batch process.
    }
}
1 Like

Yes, if you do both, it will likely fail.

Thank you, John! I appreciate any / all tips like this.

I’m always a little lost on Transaction scope (when it’s required, when it’s not required but probably should be used and why, etc.) If someone wanted to stick an explainer in the Experts Corner some time, that’d be helpful.

1 Like

I nominate @jtownsend , he seems to have a good grasp on it.

It’s like you knew I had a slow day today.

(Opens up Word and starts typing)

2 Likes

Well I understand (mostly) it, but I don’t think I could explain it very well. :person_shrugging:

Done.

1 Like

@ErpJohn
Just in case you missed it, you can check out how the system does it by dumping the sources and using the widgets in bpms and functions , then going to server/bpms folder to review the generated code, that’s how a lot of learnt.

In earlier versions you needed to had to edit the hosts.Config or the Web.Config.

Hope that helps