2017-01-14 109 views
1

我不完全理解記錄如何與Mnesia一起工作,以及改變記錄類型的效果如何。下面是例子:改變Mnesia表格/記錄類型

Erlang/OTP 17 [erts-6.2] [source] [64-bit] [async-threads:10] [kernel-poll:false] 
Eshell V6.2 (abort with ^G) 

1> c(test). 
{ok,test} 
2> mnesia:start(). 
ok 
3> test:reset_db(). 
{atomic,ok} 
4> test:add_sensor("1a0",12,erlang:now()). 
{atomic,ok} 
5> test:add_sensor("1a1",10,erlang:now()). 
{atomic,ok} 
6> test:list_sensors(). 
[{sensors,"1a0",12,{1484,392274,122051}}, 
{sensors,"1a1",10,{1484,392280,673175}}] 
7> test:list_sensors_id(). 
["1a0","1a1"] 

所以這一切是有道理的 - 我們創建了一個表(測試:reset_db)與類型的記錄「傳感器」,並增加了兩個傳感器(測試:add_sensor)。我們看到兩個「傳感器」類型的記錄。現在,讓我們修改表:

8> test:update_db(). 
{atomic,ok} 
9> test:list_sensors(). 
[{sensors_new,"1a0",12,{1484,392274,122051},0}, 
{sensors_new,"1a1",10,{1484,392280,673175},0}] 
10> test:list_sensors_id(). 
["1a0","1a1"] 
11> q(). 
ok 

所以這是我不明白的部分 - 我們更新了我們的表(測試:update_db),所以現在我們有「感應器」與「sensors_new」記錄類型的表 - 這是與我們在測試中看到的一致:list_sensors,但我沒有得到的是爲什麼test:list_sensors_id()仍然有效?在#sensors_new.name和#sensors.id之間有映射嗎? Erlang/Mnesia如何知道「X#sensors.id」和「X#sensors_new.name」在翻譯後是相同的字段?或者我錯過了什麼?

-include_lib("stdlib/include/qlc.hrl"). 
-module(test). 
-compile(export_all). 

-record(sensors,{id,val,update}). 
-record(sensors_new,{name,val,update,type}). 

reset_db() -> 
    mnesia:delete_table(sensors), 
    mnesia:create_table(sensors, [{attributes, record_info(fields, sensors)}]). 

update_db() -> 
    Transformer = fun(X) when is_record(X, sensors) -> 
    #sensors_new{name = X#sensors.id, 
       val = X#sensors.val, 
       update = X#sensors.update, 
       type = 0} end, 
    {atomic, ok} = mnesia:transform_table(sensors,Transformer,record_info(fields, sensors_new),sensors_new). 


add_sensor(Id, Val, Update) -> 
    Row = #sensors{id=Id, val=Val, update=Update}, 
    F = fun() -> 
    mnesia:write(Row) 
    end, 
    mnesia:transaction(F). 

list_sensors() -> 
    do(qlc:q([X || X <-mnesia:table(sensors)])). 

list_sensors_id() -> 
    do(qlc:q([X#sensors.id || X <-mnesia:table(sensors)])). 

do(Q) -> 
    F = fun() -> qlc:e(Q) end, 
    {atomic, Val} = mnesia:transaction(F), 
    Val. 

回答

0

快速審查第一:Erlang中的記錄只是添加記錄名作爲第一個元素的元組的語法糖。當您訪問記錄R中的N th字段時,Erlang實際上將其轉換爲使用element(N+1, R)。在這個例子中,#sensors.id#sensors_new.name都給出了相同的值2,所以訪問其中任何一個只是element(2, R)

現在,默認情況下,通過錯誤的類型訪問記錄的字段應該失敗(禁止像兩個具有相同名稱的記錄之類的東西)。如果一個變量Foo綁定到類型#sensors的記錄,但你試圖通過#sensors_new訪問的東西,好比說Foo#sensors_new.name,這通常會拋出一個badrecord錯誤,像這樣:

4> Foo = #sensors{id="bar"}. 
#sensors{id = "bar"} 
5> Foo#sensors_new.name. 
** exception error: {badrecord,sensors_new} 

然而,似乎that check is bypassed當使用QLCs(QLC解析轉換通過no_strict_record_tests,禁用「嚴格」記錄字段訪問測試)。如果我不得不猜測,我會說這是一個優化,並假設你換用後備記錄時不會使用相同的QLC。