当前位置: 首页 > news >正文

对Revit事务机制的一些推测

什么是事务机制

首先,什么是事务机制。软件事务机制是指一种在软件系统中用于管理一系列操作的方法,这些操作要么全部成功完成,要么全部失败,不会出现部分完成的情况。事务机制确保了数据的一致性和完整性,特别是在并发操作和系统故障的情况下。以下是软件事务机制的一些关键特征:
原子性(Atomicity):事务中的所有操作要么全部完成,要么全部不发生。如果事务中的任何一个操作失败,整个事务都会回滚到开始前的状态。
一致性(Consistency):事务必须使数据库从一个一致性状态转移到另一个一致性状态。在事务开始和结束时,数据库的数据完整性约束必须保持不变。
隔离性(Isolation):并发执行的事务彼此之间应该是隔离的,一个事务的执行不应该被其他事务干扰。这防止了事务之间的交互导致数据不一致。
持久性(Durability):一旦事务提交,它对系统的影响应该是永久性的。即使发生系统故障,事务的结果也应该被保留。

Revit 的事务 Transaction

从官方文档中可以看到 Revit 和事务相关的类为 Transaction,这个类的关键接口有 Start、Commit 和 Rollback。
在这里插入图片描述
在 Revit 中是需要显式得调用 Start,然后在操作完成后进行 Commit,或者操作失败后调用 Rollback。
官方例子:

public void CreatingSketch(UIApplication uiApplication)
{
    Autodesk.Revit.DB.Document document = uiApplication.ActiveUIDocument.Document;
    Autodesk.Revit.ApplicationServices.Application application = uiApplication.Application;

    // Create a few geometry lines. These lines are transaction (not in the model),
    // therefore they do not need to be created inside a document transaction.
    XYZ Point1 = XYZ.Zero;
    XYZ Point2 = new XYZ(10, 0, 0);
    XYZ Point3 = new XYZ(10, 10, 0);
    XYZ Point4 = new XYZ(0, 10, 0);

    Line geomLine1 = Line.CreateBound(Point1, Point2);
    Line geomLine2 = Line.CreateBound(Point4, Point3);
    Line geomLine3 = Line.CreateBound(Point1, Point4);

    // This geometry plane is also transaction and does not need a transaction
    XYZ origin = XYZ.Zero;
    XYZ normal = new XYZ(0, 0, 1);
    Plane geomPlane = Plane.CreateByNormalAndOrigin(normal, origin);

    // In order to a sketch plane with model curves in it, we need
    // to start a transaction because such operations modify the model.

    // All and any transaction should be enclosed in a 'using'
    // block or guarded within a try-catch-finally blocks
    // to guarantee that a transaction does not out-live its scope.
    using (Transaction transaction = new Transaction(document))
    {
       if (transaction.Start("Create model curves") == TransactionStatus.Started)
       {
           // Create a sketch plane in current document
           SketchPlane sketch = SketchPlane.Create(document,geomPlane);

           // Create a ModelLine elements using the geometry lines and sketch plane
           ModelLine line1 = document.Create.NewModelCurve(geomLine1, sketch) as ModelLine;
           ModelLine line2 = document.Create.NewModelCurve(geomLine2, sketch) as ModelLine;
           ModelLine line3 = document.Create.NewModelCurve(geomLine3, sketch) as ModelLine;

           // Ask the end user whether the changes are to be committed or not
           TaskDialog taskDialog = new TaskDialog("Revit");
           taskDialog.MainContent = "Click either [OK] to Commit, or [Cancel] to Roll back the transaction.";
           TaskDialogCommonButtons buttons = TaskDialogCommonButtons.Ok | TaskDialogCommonButtons.Cancel;
           taskDialog.CommonButtons = buttons;

           if (TaskDialogResult.Ok == taskDialog.Show())
           {
               // For many various reasons, a transaction may not be committed
               // if the changes made during the transaction do not result a valid model.
               // If committing a transaction fails or is canceled by the end user,
               // the resulting status would be RolledBack instead of Committed.
               if (TransactionStatus.Committed != transaction.Commit())
               {
                  TaskDialog.Show("Failure", "Transaction could not be committed");
               }
           }
           else
           {
               transaction.RollBack();
           }
       }
    }
}

Revit 事务机制可能的实现

大型软件的实现肯定是非常复杂的,所以这里只是一个猜测。实际情况和下面的肯定存在巨大差异。
为了支持Undo和Redo功能,我们需要在Transaction类中添加一些额外的逻辑来记录操作的历史,并在需要时回滚或重做这些操作。以下是一个简化的C#实现,其中包含了基本的Undo和Redo功能:

using System;
using System.Collections.Generic;
public class Transaction
{
    private bool isStarted;
    private Stack<Action> undoStack;
    private Stack<Action> redoStack;
    public Transaction()
    {
        undoStack = new Stack<Action>();
        redoStack = new Stack<Action>();
    }
    public void Start(string transactionName)
    {
        if (isStarted)
            throw new InvalidOperationException("Transaction has already started.");
        isStarted = true;
        Console.WriteLine($"Transaction '{transactionName}' started.");
    }
    public void Commit()
    {
        if (!isStarted)
            throw new InvalidOperationException("No transaction has been started.");
        isStarted = false;
        redoStack.Clear(); // Clear the redo stack because a new commit creates a new point of no return
        Console.WriteLine("Transaction committed.");
    }
    public void Rollback()
    {
        if (!isStarted)
            throw new InvalidOperationException("No transaction has been started.");
        while (undoStack.Count > 0)
        {
            undoStack.Pop().Invoke(); // Execute all undo actions
        }
        isStarted = false;
        Console.WriteLine("Transaction rolled back.");
    }
    public void AddAction(Action action, Action undoAction)
    {
        if (!isStarted)
            throw new InvalidOperationException("No transaction has been started. Start a transaction before adding actions.");
        undoStack.Push(undoAction); // Push the undo action onto the stack
        action.Invoke(); // Execute the action
    }
    public void Undo()
    {
        if (undoStack.Count == 0)
            throw new InvalidOperationException("No actions to undo.");
        Action undoAction = undoStack.Pop();
        undoAction.Invoke(); // Execute the undo action
        redoStack.Push(() => undoAction); // Push the inverse action onto the redo stack
    }
    public void Redo()
    {
        if (redoStack.Count == 0)
            throw new InvalidOperationException("No actions to redo.");
        Action redoAction = redoStack.Pop();
        redoAction.Invoke(); // Execute the redo action
        undoStack.Push(() => redoAction); // Push the inverse action onto the undo stack
    }
}
// Example usage:
class Program
{
    static void Main(string[] args)
    {
        Transaction transaction = new Transaction();
        transaction.Start("Sample Transaction");
        // Add actions with corresponding undo actions
        transaction.AddAction(
            () => Console.WriteLine("Action 1 performed."),
            () => Console.WriteLine("Action 1 undone.")
        );
        transaction.AddAction(
            () => Console.WriteLine("Action 2 performed."),
            () => Console.WriteLine("Action 2 undone.")
        );
        // Commit the transaction
        transaction.Commit();
        // Undo the last action
        transaction.Undo();
        // Redo the last action
        transaction.Redo();
        // Rollback the transaction (undo all actions)
        transaction.Rollback();
    }

}
在这个例子中,Transaction类有两个栈:undoStack用于存储撤销操作,redoStack用于存储重做操作。每个操作都有一个对应的撤销操作,它们一起被添加到事务中。
AddAction方法用于添加操作和对应的撤销操作到事务中。Undo和Redo方法用于执行撤销和重做操作,并相应地更新栈。
在Main方法中,我们创建了一个Transaction实例,并添加了两个操作。然后我们提交事务,执行撤销和重做操作,并最后回滚事务。
请注意,这个示例是为了演示目的而简化的。在实际应用中,操作可能涉及更复杂的状态管理,并且需要处理并发和异常情况。此外,撤销和重做操作可能需要更精细的控制,例如操作特定的对象属性或恢复到特定的状态。

**注:**思想来源于博主,部分内容来自AI

相关文章:

  • libxls库的编译以及基于Visual studio的配置
  • Qt开发中有关内存管理方面常见的问题分析与解决方案
  • 简讯:Rust 2024 edition and v1.85.0 已发布
  • 【Shell编程 / 9】脚本实战项目:从基础到进阶的自动化管理方案
  • uniapp修改picker-view样式
  • 什么是“可迭代”
  • Springboot的简单推荐实现
  • 机器学习面试八股文——决战金三银四
  • wsl配置
  • 提升C++项目编译速度
  • LDR6020 驱动的一拖多快充线,革新充电体验
  • DeepSeek 助力 Vue 开发:打造丝滑的二维码生成(QR Code)
  • 【Java基础-49.1】Java线程池之FixedThreadPool:使用、原理与应用场景详解
  • 如何调整CAN位宽容忍度?
  • 一个解析cyber record文件的python示例脚本
  • HC32F460_BootLoader
  • 构建智能AI数字人:一站式源码开发指南
  • 【Http和Https区别】
  • 企业数据集成:实现高效调拨出库自动化
  • excel中VBA宏的使用方法?
  • 深圳南澳码头工程环评将再次举行听证会,项目与珊瑚最近距离仅80米
  • 河南信阳:对违规吃喝问题不遮丑不护短,露头就打、反复敲打
  • 音乐节困于流量
  • 龚正会见哥伦比亚总统佩特罗
  • 车主质疑零跑汽车撞车后AEB未触发、气囊未弹出,4S店:其把油门当刹车
  • 商务部:中方敦促美方尽快停止232关税措施