Erasing Extensible Storage with Linked Files

Here is a query and resolution raised by Marc in the discussion forum on erasing extensible storage data with linked files, followed by a reminder of the need to regenerate the model to avoid accessing stale data and hint of possible things to come related to Revit and cloud computing:

Erasing Extensible Storage Data with Linked Files

Question: I am calling the method Schema.EraseSchemaAndAllEntities in a project containing linked documents, and it is throwing an InternalException. How can this be avoided, please?

I see a report of a similar issue in the article on deleting and updating extensible storage schema.

Can you confirm that this issue is caused by the linked files?

Answer: Basically, the Revit SDK ExtensibleStorageUtility shows you how to use this method. I believe it should work perfectly well even if entities using the schema still exist.

By the way, here is a list of most of The Building Coder extensible storage related topics.

It strikes me as rather strange that in your sample code, you only have a transaction open on the main document.

The Schema.EraseSchemaAndAllEntities method will delete storage of this schema in all open documents.

I wonder how this will affect the other linked documents if you have no transaction open for them.

I would suggest running this with only one document open in the current Revit session.

Response: I can confirm that the InternalException was caused by having projects linked in the document.

I have to unload all linked files first, run the method Schema.EraseSchemaAndAllEntities method, and then load the files again.

This is the final custom method that worked for me including the transaction:

  public void DeleteSchema()
  {
    using( Transaction trans = new Transaction( _doc ) )
    {
      trans.Start( "Delete Schema" );
      Schema schema = Schema.Lookup( _schemaGuid );
      Schema.EraseSchemaAndAllEntities( schema, false );
      trans.Commit();
    }
  }

Many thanks to Marc for exploring and solving this issue!

Regenerate to Avoid Accessing Stale Data

We have looked at numerous issues in the past where developers ran into problems – or, rather, created them for themselves – by modifying something in the model and then attempted to read the stale data without regenerating it first.

Here is another example that shows clearly how easy it can be to miss this fact if you do not make a habit of checking for this possibility as one of the first things to do when running into mysterious problems:

Question: I'm trying to find the connectors of a view using:

  collector = new FilteredElementCollector( famDoc );
  collector.OfClass( typeof( ConnectorElement ) );
 
  ICollection<ElementId> connectors
    = collector.ToElementIds();
 
  if( connectors.Count > 0 )
    view.HideElements( connectors );

This works fine if I do that on a existing 3D view, but if I create the view myself by calling CreateIsometric like this it does not:

  view = View3D.CreateIsometric( famDoc,
    viewFamilyType.Id );

Then the connectors remain visible in the view exported PNG. This also happens for any other kind of element I try to hide; it works well on an existing 3D view but not in a newly created one.

I attached a sample project that generates two pictures: one is a modification of an existing view and has the connectors hidden; the other one uses a newly generated view where the connectors cannot be hidden. If I do this inside the DocumentOpened event, none of the methods hide the connectors.

How can I hide elements in a newly created view generated by View3D.CreateIsometric, please?

Answer: I am happy to report that this problem is easy to fix and the Revit API is working properly, completely as expected.

You are creating a situation in which you are working with stale data.

If you make any modifications whatsoever to the model, you need to regenerate it again before reading.

Here are some previous examples of this kind of situation and when and how to regenerate the BIM, going all the way back to the year 2010:

The topic of regeneration is also related to the temporary transaction trick, the associated suggestion to encapsulate multiple transactions in a transaction group, commit the individual transactions and then roll bock the entire group instead.

Every time a transaction is committed, a regeneration is automatically included.

In your case, hiding the connectors and creating a new view is obviously modifying the model before it is read by the image export.

Once a to regenerate before exporting is added, the process works just the way you presumably want:

  // Hide connectors
 
  FilteredElementCollector collector
    = new FilteredElementCollector(view.Document);
 
  collector.OfClass(typeof(ConnectorElement));
 
  ICollection<ElementId> connectors
    = collector.ToElementIds();
 
  if (connectors.Count > 0)
    view.HideElements(connectors);
 
  view.Document.Regenerate(); // <---- Add this! ------
 
  // Export view

Revit and Cloud Computing

Here is a quick pointer to an interesting interview with Architosh on running Revit through a Web Browser on any device, and several other big Autodesk CAD applications as well.