I'm trying to delete the selected features in a map some of which are Utility Network Assemblies with Associations. When I execute my edit operation this error message is returned " The feature participates in a utility network and has existing association records that must be removed prior to deleting the feature."
Which seems simple enough, I need to delete the associations before trying to delete the assembly. Unfortunately I have no idea how to do that. I've looked at the sdk documentation and samples, I'm not seeing away to access associations starting from an oid and map member. I hope I'm missing something obvious. I would appreciate any ideas?
var ss = MapView.Active.Map.GetSelection();
EditOperation editOp = new EditOperation();
foreach (var item in ss)
{
foreach (var oiditem in item.Value)
{
//How to get/delete associations for this oid?
editOp.Delete(item.Key, oiditem);
}
}
editOp.Execute()
Solved! Go to Solution.
Hi Jimmy,
You can find associated features from a given feature by using the UtilityNetwork.GetAssociations. method
It takes as input an Element, which you can create using UtilityNetwork.CreateElement.
If you don't have a UtilityNetwork object, this snippet shows how to obtain one from a Table.
I hope this helps,
--Rich
Hi Jimmy,
You create an `AssociationDescription` object, and pass that to the `EditOperation.Delete` overload that takes one. The association description object describes an association to delete (or create, in other workflows)
For your code above:
AssociationDescription associationToDelete = new AssociationDescription(a.Type, new RowHandle(a.FromElement, un), new RowHandle(a.ToElement, un);
ediOp.Delete(associationToDelete);
--Rich
Hi Jimmy,
You can find associated features from a given feature by using the UtilityNetwork.GetAssociations. method
It takes as input an Element, which you can create using UtilityNetwork.CreateElement.
If you don't have a UtilityNetwork object, this snippet shows how to obtain one from a Table.
I hope this helps,
--Rich
Thanks for the quick response @RichRuh, you got me over that hump. I would not have thought to use CreateElement, I was looking for something like GetElement. But I'm still missing something on how to delete the associations. When I use UtilityNetwork.DeleteAssociation I get an exception (The current operation requires an edit operation). I also see that EditOperation.Delete has an overload for an AssociationDescription but I don't see to instantiate that object from an Association or Element.
//Used the snippet to get utility network
var un = GetUtilityNetwork();
foreach (var item in ss)
{
var featureLayer = item.Key as BasicFeatureLayer;
if (featureLayer.Name.Contains("ASSEMBLY"))
{
EditOperation editOp = new EditOperation();
var qf = new QueryFilter() { ObjectIDs = item.Value };
RowCursor sr = featureLayer.Search(qf);
while (sr.MoveNext())
{
Row tempfeat = sr.Current;
try
{
var ele = un.CreateElement(tempfeat);
var assocs = un.GetAssociations(ele);
foreach (var a in assocs)
{
un.DeleteAssociation(a);
/*
ArcGIS.Core.Data.GeodatabaseGeneralException: The current operation requires an edit operation.
---> System.Runtime.InteropServices.COMException: TabletPC inking error code. Initialization failure (Exception from HRESULT: 0x80040223)
at ArcGIS.Core.Internal.IUtilityNetworkIOP.UtilityNetwork_DeleteContainmentAssociation(IntPtr utilityNetworkHandle, Int32 containerSourceID, Guid containerGlobalID, Int32 contentSourceID, String[] contentGlobalIDs)
at ArcGIS.Core.Data.UtilityNetwork.UtilityNetwork.DeleteAssociation(Association association)
--- End of inner exception stack trace ---
at ArcGIS.Core.Data.UtilityNetwork.UtilityNetwork.DeleteAssociation(Association association)
at MyTools.Button1.<OnClick>b__1_0()
*/
}
editOp.Delete(tempfeat);
}
catch (Exception ex)
{
//log.Error(ex, $"Oid {tempfeat.GetObjectID()}");
}
}
var t = editOp.Execute();
}
}
Hi Jimmy,
You create an `AssociationDescription` object, and pass that to the `EditOperation.Delete` overload that takes one. The association description object describes an association to delete (or create, in other workflows)
For your code above:
AssociationDescription associationToDelete = new AssociationDescription(a.Type, new RowHandle(a.FromElement, un), new RowHandle(a.ToElement, un);
ediOp.Delete(associationToDelete);
--Rich
Now let's talk about this line...
if (featureLayer.Name.Contains("ASSEMBLY"))
When you define your utility network schema, you can set the association deletion semantics for a container or structure type. You can see these in the Network Properties dialog that you can get by right-clicking on the utility network layer.
There are three values for this setting:
Now the reason this setting exists is to prevent users from accidentally deleting a container that contains a large number of features- like a large switching cabinet or even a substation.
I would consider two things.
1. Instead of looking for the name "Assembly", ask the feature if it is a container and, if so, what is the association deletion semantics. You can do this as follows:
bool needToDeleteAssociations = false;
Element element = un.CreateElement(tempFeat);
AssetType assetType = element.AssetType;
if (assetType.AssociationRoleType == AssociationRoleType.Container) {
if (assetType.AssociationDeletionSemantics == AssociationDeleteType.Restricted) {
needToDeleteAssociations = true;
}
}
(Structures can have association deletion semantics too)
2. The second thing to consider is... should you be doing this? The schema was defined to restrict deletion of these containers. Was it intentional? If so, your code is... well... subverting that setting. If it wasn't intentional, maybe the right solution isn't to write any code at all but to change the schema to not have this setting...
I can't answer the question for you, but I would encourage you to ask it if you haven't already.
--Rich
Good information Rich. For additional context we have decided that the assemblies we originally created in the migration process are not providing value and are making editing more difficult. The code I'm working on will allow us to "clean up" these assemblies we no longer want and do some other house keeping that I didn't include in my pseudo code.
In case someone (future me perhaps) comes across this post I'm posting my latest code.
//Used the snippet to get utility network
var un = GetUtilityNetwork();
foreach (var item in ss)
{
var featureLayer = item.Key as BasicFeatureLayer;
if (featureLayer.Name.Contains("ASSEMBLY"))
{
EditOperation editOp = new EditOperation();
var qf = new QueryFilter() { ObjectIDs = item.Value };
RowCursor sr = featureLayer.Search(qf);
while (sr.MoveNext())
{
Row tempfeat = sr.Current;
try
{
var ele = un.CreateElement(tempfeat);
var assocs = un.GetAssociations(ele);
foreach (var a in assocs)
{
AssociationDescription associationToDelete = new AssociationDescription(a.Type, new RowHandle(a.FromElement, un), new RowHandle(a.ToElement, un));
editOp.Delete(associationToDelete);
}
editOp.Delete(tempfeat);
}
catch (Exception ex)
{
//log.Error(ex, $"Oid {tempfeat.GetObjectID()}");
}
}
var t = editOp.Execute();
var editOpChain = editOp.CreateChainedOperation();
if (t)
{
editOpChain.Delete(ss);
t = editOpChain.Execute();
}
}
}