【问题标题】:Merging records for Mnesia合并 Mnesia 的记录
【发布时间】:2010-09-08 21:37:37
【问题描述】:

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

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

我的问题当然是记录....我找不到动态创建它们或将其中 2 个合并在一起或任何其他方法。最好有一个我可以调用的函数:

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

【问题讨论】:

    标签: erlang mnesia


    【解决方案1】:

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

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

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

    访问函数的命名约定可能看起来很奇怪,但灵感来自 Richard O'Keefe 的提议。它至少是一致的,并且不太可能与现有功能发生冲突。 (:

    【讨论】:

    • 快速浏览一下这可能不是我想要的。但有趣的是,我稍后会检查。
    【解决方案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).
    

    您可以随意使用它。

    【讨论】:

      猜你喜欢
      • 2017-01-21
      • 2018-09-18
      • 2017-05-29
      • 1970-01-01
      • 2011-09-05
      • 2015-03-20
      • 2011-07-29
      • 1970-01-01
      • 2012-05-03
      相关资源
      最近更新 更多