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

对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


http://www.kler.cn/a/557752.html

相关文章:

  • Webpack的基本功能有哪些
  • 负载均衡集群( LVS 相关原理与集群构建 )
  • RT-Thread+STM32L475VET6——icm20608传感器
  • 可变参数学习
  • 论文略:ACloser Look into Mixture-of-Experts in Large Language Models
  • 详解单例模式、模板方法及项目和源码应用
  • 基于Spring Boot的兴顺物流管理系统设计与实现(LW+源码+讲解)
  • Linux提权篇之内核提权(三)
  • Rust并发编程实践:10分钟入门系统级编程
  • reacct hook useState
  • Linux 在云计算中的应用有哪些?
  • Flutter 启动优化
  • Part 3 第十二章 单元测试 Unit Testing
  • 二叉树-翻转二叉树
  • Spring Boot项目@Cacheable注解的使用
  • 探索YOLO技术:目标检测的高效解决方案
  • ChatGPT平替自由!DeepSeek-R1私有化部署全景攻略
  • vue3 采用xlsx库实现本地上传excel文件,前端解析为Json数据
  • 【Java高级篇】——第16篇:高性能Java应用优化与调优
  • 07.Docker 数据管理