Having Issues with DB.SaveAs()

Having Issues with DB.SaveAs()

Poncho_Slim
Enthusiast Enthusiast
911 Views
10 Replies
Message 1 of 11

Having Issues with DB.SaveAs()

Poncho_Slim
Enthusiast
Enthusiast

I am able to .Commit() but my .SaveAs keeps failing. I am thinknig it could be due to functions running before this that is causing the issue, but I am at a loss. I am opening Databases and reading DWG files, and for some reason I am feeling as if I am not "Closing" them in other functions previously to this, causing the SaveAs error. It feels odd though since I am able to Save ass this file in a previous function, but in this function, it is unsuccessful.

private void VPFreezeLayerInAllViewportsExceptCurrent(Dictionary<string, LayerTableRecord> LayersToManipulate, string FileName, string MainSheet, string RSSheet)
{
    var originalDB = HostApplicationServices.WorkingDatabase;
    // Open the drawing
    Database database = new Database(false, true);
    database.ReadDwgFile(FileName, FileOpenMode.OpenForReadAndAllShare, true, "");
    database.CloseInput(true);
    HostApplicationServices.WorkingDatabase = database;
    using (Transaction tr = database.TransactionManager.StartTransaction())
    {
        // Get the Layout Dictionary and Layer Table
        DBDictionary layoutDict = tr.GetObject(database.LayoutDictionaryId, OpenMode.ForRead) as DBDictionary;
        LayerTable layerTable = (LayerTable)tr.GetObject(database.LayerTableId, OpenMode.ForRead);
        IEnumerator<ObjectId> LayersToFreeze = DictionaryToIEnumerator(LayersToManipulate);
        // Loop through the Layouts
        foreach (DBDictionaryEntry layoutIDs in layoutDict)
        {
            Layout layout = tr.GetObject(layoutIDs.Value, OpenMode.ForRead) as Layout;
            // Once you land on the Main Sheet or RSSheet
            if (layout.LayoutName != MainSheet && layout.LayoutName != RSSheet && layout.LayoutName != "Model")
            {
                // Get the Viewports via the LayoutsBlock Table
                BlockTableRecord LayoutBlockTableRecord = tr.GetObject(layout.BlockTableRecordId, OpenMode.ForRead) as BlockTableRecord;
                foreach (ObjectId id in LayoutBlockTableRecord)
                {
                    Viewport viewport = tr.GetObject(id, OpenMode.ForRead) as Viewport;
                    if (viewport != null)
                    {
                        viewport.UpgradeOpen();
                        viewport.FreezeLayersInViewport(LayersToFreeze);
                        LayersToFreeze = DictionaryToIEnumerator(LayersToManipulate);
                    }
                }
            }

        }
        tr.Commit();
        database.SaveAs(FileName, DwgVersion.Current);
    }
    HostApplicationServices.WorkingDatabase = originalDB;
}



There might be some questionable code in here since I am just trying to get things to work, and I can optimize it later (HostApplicationServices...).
Any pointers or ideas is highly appreciated. 

0 Likes
912 Views
10 Replies
Replies (10)
Message 2 of 11

norman.yuan
Mentor
Mentor

You may want to try to move the database.SaveAs(...) outside of the using (Transaction tran....){... ...}. Of course you also need to dispose the database after SaveAs() - you should create new datagase like this:

var originalDb=Host.....WorkingDatabase;

using (Database database=new  Database(false, true))

{

   datase.ReadDwgFile(...);

   Host...WorkingDatabase=database;

   using (Transaction tran=...())

   {  

      ... 

      tran. Commit();

   }

   database.SaveAs(...);

}

Host...WorkingDatabase=originalDb;

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 3 of 11

Poncho_Slim
Enthusiast
Enthusiast

I attempted to do this, even on previously Database opening functions, but I am still getting the same error. For more context, the error is: Autodesk.AutoCAD.Runtime.Exception: 'eFileInternalErr'

 

0 Likes
Message 4 of 11

ActivistInvestor
Mentor
Mentor

There's no problem with calling SaveAs() within the using(Transaction) {} scope, because you already called Commit() which means that Dispose() does nothing at all.

 

I would suggest trying to save the file to a different filename that doesn't already exist, and see if the error persists.

 

Also, what is the purpose of this:

 

DictionaryToIEnumerator()

 

You shouldn't be using an IEnumerator<T> directly unless you're implementing some kind of iterator that uses yield return, etc.  An IEnumerator<T> is an IDisposable, that must be disposed. 

 

But, if you insist on using an IEnumerator<T>, you should manage it with 'using(IEnumerator<T> enumerator =...){}

0 Likes
Message 5 of 11

Poncho_Slim
Enthusiast
Enthusiast

Okay ill try this one moment

0 Likes
Message 6 of 11

Poncho_Slim
Enthusiast
Enthusiast

Poncho_Slim_0-1710364667937.png

I attempted to do this, but it did not seem to work:

private void VPFreezeLayerInAllViewportsExceptCurrent(Dictionary<string, LayerTableRecord> LayersToManipulate, string FileName, string MainSheet, string RSSheet)
{
    // Open the drawing
    var originalDB = HostApplicationServices.WorkingDatabase;
    using (Database database = new Database(false, true))
    {
        database.ReadDwgFile(FileName, FileOpenMode.OpenForReadAndAllShare, true, "");
        HostApplicationServices.WorkingDatabase = database;
        database.CloseInput(true);
        using (Transaction tr = database.TransactionManager.StartTransaction())
        {
            // Get the Layout Dictionary and Layer Table
            DBDictionary layoutDict = tr.GetObject(database.LayoutDictionaryId, OpenMode.ForRead) as DBDictionary;
            LayerTable layerTable = (LayerTable)tr.GetObject(database.LayerTableId, OpenMode.ForRead);
            IEnumerator<ObjectId> LayersToFreeze = DictionaryToIEnumerator(LayersToManipulate);
            // Loop through the Layouts
            foreach (DBDictionaryEntry layoutIDs in layoutDict)
            {
                Layout layout = tr.GetObject(layoutIDs.Value, OpenMode.ForRead) as Layout;
                // Once you land on the Main Sheet or RSSheet
                if (layout.LayoutName != MainSheet && layout.LayoutName != RSSheet && layout.LayoutName != "Model")
                {
                    // Get the Viewports via the LayoutsBlock Table
                    BlockTableRecord LayoutBlockTableRecord = tr.GetObject(layout.BlockTableRecordId, OpenMode.ForRead) as BlockTableRecord;
                    foreach (ObjectId id in LayoutBlockTableRecord)
                    {
                        Viewport viewport = tr.GetObject(id, OpenMode.ForRead) as Viewport;
                        if (viewport != null)
                        {
                            viewport.UpgradeOpen();
                            viewport.FreezeLayersInViewport(LayersToFreeze);
                            LayersToFreeze = DictionaryToIEnumerator(LayersToManipulate);
                        }
                    }
                }
            }
            tr.Commit();
        }
        database.SaveAs("C:\\Users\\andy\\Desktop\\Test1file.dwg", DwgVersion.Current);
    }
    HostApplicationServices.WorkingDatabase = originalDB;
}



0 Likes
Message 7 of 11

ActivistInvestor
Mentor
Mentor
IEnumerator<ObjectId> LayersToFreeze = DictionaryToIEnumerator(LayersToManipulate);

 

You didn't address the issue I raised about the improper use of IEnumerator<T>. AutoCAD Iterators can be very finicky and can rely on being properly disposed.

 

Your code doesn't dispose them. If you want further help, post the DictionaryToEnumerator() method so we can see what's going on.

0 Likes
Message 8 of 11

Poncho_Slim
Enthusiast
Enthusiast

Oh my apologies.
Here is my DictionaryToIEnumerator() function:

 

private IEnumerator<ObjectId> DictionaryToIEnumerator(Dictionary<string, LayerTableRecord> LayersToManipulate)
{
    foreach (LayerTableRecord layer in LayersToManipulate.Values)
    {
        yield return layer.ObjectId;
    }
}

I tried to just get this to work, this was the easiest way to get this. I would not mind any other way to return a IEnumerator or a related object

 

0 Likes
Message 9 of 11

ActivistInvestor
Mentor
Mentor

You can eliminate that method and just use the Values property of the Dictionary, as it's the same thing.

 

My suspicion is that your problem may be with the paper space viewport. Each layout contains a paper space viewport that is not a floating viewport. You probably need to avoid operating on it. Instead of operating on the layout block, You should just use the Layout's GetViewports() method, and skip the first ObjectId, which is always the paper space viewport. Or, you can open all of the Viewports and skip the one whose Number property == 1. There's no need to access the Layout block to get a layout's viewports.

0 Likes
Message 10 of 11

Poncho_Slim
Enthusiast
Enthusiast

Is there any way to be able to get more information on the error. I keep getting eFilerError, but no supporting information. This error comes up so much and I have NO way of learning what could be causing it. I kind of repaired the code, but it still occasionally hits another eFilerError for seemingly no reason.

0 Likes
Message 11 of 11

ActivistInvestor
Mentor
Mentor

Did you make the change I suggested to avoid operating on the paper space viewport (the one whose Number property == 1) ?

 

One more thing to try is to restore the original working database before you call SaveAs(). SaveAs() doesn't require a database to be the current working database.

 

To rule out other unrelated causes for the eFilerError, when it happens, open the drawing you were trying to save to in the editor and run the AUDIT command.

0 Likes