简体   繁体   English

“堆栈空间不足”在 vba 中使用递归函数进行访问

[英]"Out of stack space" with a Recursive function in vba for Access

I'm reaching out to you because I'm getting troubles coding a module for an Access program.我联系您是因为我在为 Access 程序编写模块时遇到了麻烦。

Introduction:介绍:

I got 4 Tables: Products, Receipes, Ordonnancement & Commands.我有 4 个表:产品、收据、军械和命令。 Ordonnancement and Commands have the same structure, the second one being the result of the processing of the commands through the receipes. Ordonnancement 和 Commands 具有相同的结构,第二个是通过receipes 处理命令的结果。

Goal of the VBA Module: VBA 模块的目标:

I'm creating a Module to create records to the Ordonnancement table by processing the commands through the receipes.我正在创建一个模块,通过处理接收到的命令来为 Ordonnancement 表创建记录。 In detail, I use a recursive function to cope with the variable deepth of the receipes that allows me to loop through the Receipes Table and generate the need in all Products for one date.详细地说,我使用递归函数来处理收据的可变深度,这使我可以遍历收据表并在所有产品中生成一个日期的需求。

Remarks:评论:

-I normally work in C# using EF to work with databases. - 我通常在 C# 中使用 EF 来处理数据库。 After several tries to use directly the RecordSet possibilities of Access, I decided to generate POCO classes for ReceipeLign and OrdoLign, to stock the data of the tables in collections of those objects, work with those and then commit to the Access tables adding records to each RecordSet.在多次尝试直接使用 Access 的 RecordSet 可能性之后,我决定为 ReceipeLign 和 OrdoLign 生成 POCO 类,将表的数据存储在这些对象的集合中,处理这些数据,然后提交到 Access 表,向每个表添加记录记录集。

-I work in french, so I translated a few things so it can be understood by everyone. -我用法语工作,所以我翻译了一些东西,以便大家都能理解。 It might not be perfect, let me know if not clear.它可能不完美,如果不清楚,请告诉我。

Code:代码:

Option Compare Database
Option Explicit

Dim cnc As New ADODB.Connection
Dim CRecordSet As New ADODB.Recordset
Dim FTRecordSet As New ADODB.Recordset
Dim ORecordSet As New ADODB.Recordset

Public Sub GenerateOrdonnancement()

'Retrieving info from tables Commandes & FT in RecordSets.
Set cnc = CurrentProject.Connection
Set CRecordSet = cnc.Execute("SELECT * FROM Commandes")
Set FTRecordSet = cnc.Execute("SELECT * FROM FichesTechniques")
Set ORecordSet = cnc.Execute("SELECT * FROM Ordonnancement")

'Creation of the list to receive data from the tables
Dim Commandes As New Collection
Dim FicheTechniques As New Collection

'Retrieving commands and receipes
Dim Commande As ligneOrdo
Dim ordo As ligneOrdo
Dim FT As ligneFT

Do Until CRecordSet.EOF

    Set Commande = New ligneOrdo
    Commande.DateCommande = CRecordSet("dateCommande").Value
    Commande.Produit = CRecordSet("Produit").Value
    Commande.Quantite = CRecordSet("quantite").Value
    Commandes.Add Commande
    CRecordSet.MoveNext

Loop
CRecordSet.Close


Do Until FTRecordSet.EOF

    Set FT = New ligneFT
    FT.Nom = FTRecordSet("Nom").Value
    FT.Ingredient = FTRecordSet("Ingredient").Value
    FT.Quantite = FTRecordSet("quantité").Value
    FT.IsComposed = FTRecordSet("Composé").Value
    FicheTechniques.Add FT
    FTRecordSet.MoveNext

Loop
FTRecordSet.Close


'creation of the collection of ordo
'Later: versionning of the Ordonnancements
Dim AProduire As New Collection

Dim mr As ligneOrdo
For Each mr In Commandes
    Dim coll As Collection
    Set coll = CreateOrdoLigne(mr, FicheTechniques)
    Dim item As New ligneOrdo
    For Each item In coll
        AProduire.Add item
    Next item
Next mr

'Adding and saving the coll AProduire in the RecordSetO
cnc.BeginTrans
Dim item2 As ligneOrdo
For Each item2 In AProduire
    ORecordSet.AddNew
    ORecordSet("DateCommande").Value = item2.DateCommande
    ORecordSet("Produit").Value = item2.Produit
    ORecordSet("Quantite").Value = item2.Quantite
    ORecordSet.Update
Next item2

ORecordSet.Close

cnc.CommitTrans

End Sub

Function CreateOrdoLigne(ligne As ligneOrdo, FT As Collection) As Collection

Dim ordo As New Collection

Dim ligneFT As Variant
'Loop through the receipes
For Each ligneFT In FT
    If ligneFT.Nom = ligne.Produit Then
        Dim AProduire As New ligneOrdo
        AProduire.Produit = ligneFT.Ingredient
        AProduire.DateCommande = ligne.DateCommande
        AProduire.Quantite = ligne.Quantite * ligneFT.Quantite
        ordo.Add AProduire
        If ligneFT.IsComposed = True Then
            Dim ordoList2 As New Collection
            Set ordoList2 = CreateOrdoLigne(AProduire, FT)
            Dim recordOrdo As ligneOrdo
            For Each recordOrdo In ordoList2
                ordo.Add recordOrdo
            Next recordOrdo
            Set ordoList2 = Nothing
        End If
        Set AProduire = Nothing
    End If
Next ligneFT


Set CreateOrdoLigne = ordo

End Function

Problem Statement:问题陈述:

Running the Module, I get a Run-Time Error 28 : "Out of stack Space", which seems after some reseach a common thing working with recursive functions in such tight environnements.运行模块,我得到一个运行时错误 28:“堆栈空间不足”,这似乎是经过一些研究后在如此紧凑的环境中使用递归函数的常见问题。 Problem is, I can't really optimize the process.问题是,我无法真正优化流程。 I am looking for direct ways to bypass this error or ideas to tackle this problem in another way.我正在寻找绕过此错误的直接方法或以另一种方式解决此问题的想法。

Thank you all,谢谢你们,

So after some debuging with @Andre 's help, I found out that the recursivity was infinite, hence the error on the size.所以在@Andre 的帮助下进行了一些调试后,我发现递归是无限的,因此大小错误。 Even with that, Access was not able to generate so much data and stock it somewhere beforme commiting those changes to the database.即便如此,Access 也无法在将这些更改提交到数据库之前生成如此多的数据并将其存储在某个地方。

I have found a way around that problem, which consists in:我找到了解决该问题的方法,其中包括:

  • avoiding using functions to be stocked in a collection.避免使用存储在集合中的函数。 I therefore transformed the function into a sub.因此,我将函数转换为子函数。
  • commiting the changes to the database along the generation process.在生成过程中提交对数据库的更改。
  • obj = Nothing when it is not needed anymore in a repeatable process. obj = 当在可重复的过程中不再需要它时,什么都没有。

What I have learnt and maybe could help others我所学到的,也许可以帮助别人

  • Analyse the recursive process to see what could make it infinite, define error handlers accordingly分析递归过程,看看是什么使它无限,相应地定义错误处理程序
  • Debug.Print is an efficient way to debug in vba ACCESS, to generate data and check the whole process. Debug.Print 是一种在vba ACCESS 中进行调试、生成数据和检查整个过程的有效方法。

Thank you @Andre and the others for your time, hope it will help others.谢谢@Andre 和其他人的时间,希望它能帮助别人。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM