你好,
所以,我有一段相当复杂的 JMP 脚本,它以一种奇怪的方式失败了,我想了解原因。在开始之前,我先为它的复杂性道歉。
我编写了一个库,我们将其称为 sql_lib.jsl,它定义了一个命名空间“sql_lib”。在该命名空间中,我定义了一个名为“sql_lib:QueryBatchService”的 clsQueryBatch 类。该类的目的是使多个 sql 查询能够轻松地在后台同时批处理。这个想法是,当实例化一个 sql_lib:QueryBatchService 类型的对象时,就可以向该对象添加查询,然后调用类方法 run_queries() 来启动所有查询,最后使用类方法 get_results() 获取所有查询的结果。这个类的完整实现并不重要,但我的方法如下:该类的 _ init _() 方法根据传递的参数设置一些成员变量,例如要使用的数据库会话和结果表所需的可见性级别,重要的是,它还创建了一个匿名命名空间 this:m_ns,我在其中存储和检索查询结果以及已完成/错误的查询数量。 _ init _ 方法如下所示(注意,我还为数据库连接创建了一个名为 sql_lib:DBSession 的包装类,其目的是为每个数据库连接赋予一个名称,以便我可以轻松地跟踪和重用同一个连接进行多个查询,并在出现错误时重新连接):
_init_ = Method({
db_session,
visibility = 1
},
If(! (db_session<<GETNAME></GETNAME>
Once the object is instantiated, I add queries to the queue with add_query():
<CODE class=" language-jsl">add_query = Method({query_str,query_name},
If(!IsString(query_str),
Write("clsQueryBatch:add_query requires an SQL query string as a parameter.\!N");
Throw();
);
query = NewSQLQuery(Connection(m_dbc), CustomSQL(query_str));
query << Query Name(query_name);
m_queries[query_name]=query;
m_ns:total++;
);
And I can then launch all queued queries with run_queries(). This is where the weirdness happens. You’ll notice that I’ve created an Associative Array variable in the anonymous m_ns namespace called results. This should be available as m_ns:results, and I take advantage of this by wrapping the code that runs the queries in Eval(EvalExpr()) and injecting the m_ns_name member variable as an expression into the OnRunComplete method of the RunBackground message sent to each query. I recently changed m_ns:results from a List to an Associative Array because I needed to be able to ensure that I could track down multiple differently named result tables. When I was using a list to track the results, this code worked fine, but when I try to assign a value into the Associative Array, I get the error “Not subscriptable value in access or evaluation of 'Assign' , ns:results[key] = /*###*/queryResult/*###*/“. Preamble completed, here’s the code for run_queries():
<CODE class=" language-jsl">run_queries = Method({},
If(m_visibility==1,
ForEach({{query_name,query},idx}, m_queries,
Eval(
EvalExpr(
query << RunBackground(
OnRunComplete(
Write("Query complete.\!N");
ns = Namespace(Expr(m_ns_name));
key = Eval(Expr(query_name));
Show(ns:results,Type(ns:results),key,queryResult);
ns:results[key] = queryResult;
ns:complete++;
),
OnRunCanceled(
Write("Query cancelled.\!N");
ns = Namespace(Expr(m_ns_name));
ns:error++;
),
OnError(
Write("Query failed!\!N");
ns = Namespace(Expr(m_ns_name));
ns:error++;
)
)
)
)
)
, //else
ForEach({{query_name,query},idx}, m_queries,
Eval(
EvalExpr(
query << RunBackground(
OnRunComplete(
ns = Namespace(Expr(m_ns_name));
key = Eval(Expr(query_name));
Show(ns:results,Type(ns:results),key,queryResult);
ns:results[key] = queryResult;
ns:complete++;
),
Invisible,
OnRunCanceled(
Write("Query cancelled.\!N");
ns = Namespace(Expr(m_ns_name));
ns:error++;
),
OnError(
ns = Namespace(Expr(m_ns_name));
Write("Query failed!\!N");
ns:error++;
)
)
)
)
)
)
);
As you can see, I’ve put a few Show() statements in here to try to understand what’s happening. The results of those are what prompts my question. Please also note that the query runs and generates a data table as expected, the problem arises when I try to store a reference to that data table for later use.
<CODE class=" language-jsl">Show(ns:results,Type(ns:results),key,queryResult);
puts this in the log:
<CODE class=" language-jsl">ns:results = [=>];
Type(ns:results) = "Associative Array";
key = "subid_temp_table_data";
queryResult = DataTable("subid_temp_table_data");so clearly the namespace is resolving correctly, and the type of ns:results is Associative array, and key is a string, queryResult is a datatable, but for some reason I am unable to create a new key=>value pair in the ns:results AA. Remember, this worked when ns:results was a list and I used Insert Into(ns:results, queryResult). Is there a difference in the memory context for lists and associative arrays that I’m violating in some way here? Usually in the past when calling RunBackground and using the OnRunComplete context, I’ve used a global variable to hold the results of the query, is this an issue with my nested namespace:class:namespace structure? Any insight you can provide would be greatly appreciated.
感谢 JMP 支持部门的 Jasean,事实证明,发生此错误是因为我在初始化结果关联数组时使用了 AssociativeArray() 函数。将其更改为使用 [=>] 符号解决了我的问题。
当您调用 AssociativeArray() 时,它显然会返回构造函数对象,因此每当我实例化新对象时,关联数组都会被覆盖。通过静态地将成员变量分配为 [=>] 对象,它不会被覆盖,至少这是我从@Jasean的电子邮件中得到的启示,也许他可以给出更多的解释。