我在mnesia
中存储了一些数据,我希望能够更改大部分值。
天真的
change(RecordId, Slot, NewValue) ->
[Rec] = do(qlc:q([X || X <- mnesia:table(rec), X#rec.id =:= RecordId])),
NewRec = Rec#rec{Slot=NewValue},
F = fun() -> mnesia:write(NewRec) end,
{atomic, Val} = mnesia:transaction(F),
Val.
不这样做;编译器抱怨Slot
不是atom
或_
。有没有办法像上面那样表达一般的插槽编辑功能,或者我将被困在定义一大堆change_slot
s?
稍微好一点的方法是提取insert
和find
件
atomic_insert(Rec) ->
F = fun() -> mnesia:write(Rec) end,
{atomic, Val} = mnesia:transaction(F),
Val.
find(RecordId) ->
[Rec] = do(qlc:q([X || X <- mnesia:table(rec), X#rec.id =:= RecordId])),
Rec.
change(RecordId, name, NewValue) ->
Rec = find(RecordId),
NewRec = Rec#rec{name=NewValue},
atomic_insert(NewRec);
change(RecordId, some_other_property, NewValue) ->
Rec = find(RecordId),
NewRec = Rec#rec{some_other_property=NewValue},
...
但那里仍然有一些代码重复。有没有办法抽出那个模式?是否有既定的技术可以编辑记录?一般的想法吗?
答案 0 :(得分:4)
由于记录由元组表示,您可以尝试使用元组操作来设置单个值。
-module(rec).
-export([field_num/1, make_rec/0, set_field/3]).
-record(rec, {slot1, slot2, slot3}).
make_rec() ->
#rec{slot1=1, slot2=2, slot3=3}.
field_num(Field) ->
Fields = record_info(fields, rec),
DifField = fun (FieldName) -> Field /= FieldName end,
case length(lists:takewhile(DifField, Fields)) of
Length when Length =:= length(Fields) ->
{error, not_found};
Length ->
Length + 2
end.
set_field(Field, Value, Record) ->
setelement(field_num(Field), Record, Value).
set_field将返回更新的记录:
Eshell V5.9.1 (abort with ^G)
1> c(rec).
{ok,rec}
2> A = rec:make_rec().
{rec,1,2,3}
3> B = rec:set_field(slot3, other_value, A).
{rec,1,2,other_value}
答案 1 :(得分:3)
您还可以将change
定义为宏(特别是如果它仅在模块内部使用):
-define(change(RecordId, Slot, NewValue),
begin
[Rec] = do(qlc:q([X || X <- mnesia:table(rec), X#rec.id =:= RecordId])),
NewRec = Rec#rec{Slot=NewValue},
F = fun() -> mnesia:write(NewRec) end,
{atomic, Val} = mnesia:transaction(F),
Val
end).
用法:
test(R, Id) ->
?change(Id, name, 5).
使用宏,您还可以将_
作为字段传递(适用于模式匹配)。
答案 2 :(得分:2)
使用该记录的另一种方式实际上是一个元组:
change(RecordId, Index, NewValue) ->
[Rec] = do(qlc:q([X || X <- mnesia:table(rec), X#rec.id =:= RecordId])),
NewRec = setelement(Index, Rec, NewValue),
F = fun() -> mnesia:write(NewRec) end,
{atomic, Val} = mnesia:transaction(F),
Val.
你可以这样使用:
5> Val = record:change(id58, #rec.name, new_value).
这也是记录作为元组的“干净”使用,因为您使用#rec.name
语法来查找元组中字段的索引。这就是添加此语法的原因。