合并Mnesia的记录

时间:2008-09-15 11:54:17

标签: erlang mnesia

我正在尝试重构一些代码,用于收集调用队列中代理的当前状态的软件。目前,对于我收听的6个左右的事件中的每一个,我检查Mnesia表是否存在代理并根据事件更改行中的某些值,或者如果代理不存在则将其添加为新的。目前我在每个事件中都有这个Mnesia事务,当然这是一堆用于检查代理存在的重复代码等等。

我正在尝试更改它,以便有一个像 change_agent / 2 这样的函数,我从为我处理此事件的事件中调用。

我的问题当然是记录....我发现无法动态创建它们或将它们中的两个合并在一起或任何东西。最好有一个我可以称之为的函数:

change_agent("001", #agent(id = "001", name = "Steve")).
change_agent("001", #agent(id = "001", paused = 0, talking_to = "None")).

2 个答案:

答案 0 :(得分:3)

很难为记录编写通用访问函数。 一个解决方法是'exprecs'库,其中 将为低级记录访问函数生成代码。

您需要做的是添加以下行 一个模块:

-compile({parse_transform, exprecs}).
-export_records([...]).  % name the records that you want to 'export'

访问功能的命名约定可能看起来很奇怪,但受到了Richard O'Keefe提议的启发。它至少是一致的,不太可能与现有功能发生冲突。 (:

答案 1 :(得分:2)

我刚才写了一些代码,合并了两个记录。不完全是动态的,但是你可以轻松地将它用于多个记录。

它的工作方式如下:merge / 2函数接受两个记录并将它们与空记录一起转换为列表以供参考(记录类型在编译时定义,必须是。这是“动态”部分) 。然后通过泛型函数merge / 4运行它们,它与列表一起使用,如果它们被定义则从A获取元素,否则从B中定义它们,或者最后来自Default(总是定义)。

这是代码(请原谅StackOverflow糟糕的Erlang语法突出显示):

%%%----------------------------------------------------------------------------
%%% @spec merge(RecordA, RecordB) -> #my_record{}
%%%     RecordA = #my_record{}
%%%     RecordB = #my_record{}
%%%
%%% @doc Merges two #my_record{} instances. The first takes precedence.
%%% @end
%%%----------------------------------------------------------------------------
merge(RecordA, RecordB) when is_record(RecordA, my_record),
                             is_record(RecordB, my_record) ->
    list_to_tuple(
        lists:append([my_record],
                     merge(tl(tuple_to_list(RecordA)),
                           tl(tuple_to_list(RecordB)),
                           tl(tuple_to_list(#my_record{})),
                           []))).

%%%----------------------------------------------------------------------------
%%% @spec merge(A, B, Default, []) -> [term()]
%%%     A = [term()]
%%%     B = [term()]
%%%     Default = [term()]
%%%
%%% @doc Merges the lists `A' and `B' into to a new list taking
%%% default values from `Default'.
%%%
%%% Each element of `A' and `B' are compared against the elements in
%%% `Default'. If they match the default, the default is used. If one
%%% of them differs from the other and the default value, that element is
%%% chosen. If both differs, the element from `A' is chosen.
%%% @end
%%%----------------------------------------------------------------------------
merge([D|ATail], [D|BTail], [D|DTail], To) ->
    merge(ATail, BTail, DTail, [D|To]); % If default, take from D
merge([D|ATail], [B|BTail], [D|DTail], To) ->
    merge(ATail, BTail, DTail, [B|To]); % If only A default, take from B
merge([A|ATail], [_|BTail], [_|DTail], To) ->
    merge(ATail, BTail, DTail, [A|To]); % Otherwise take from A
merge([],        [],        [],        To) ->
    lists:reverse(To).

随意以任何您想要的方式使用它。