2009-04-06 7 views
3

Supposons que j'ai une définition simple d'enregistrement:Quel est le meilleur moyen d'empêcher l'ajout d'un enregistrement dont la clé primaire est déjà présente en Mnesia?

-record(data, {primary_key = '_', more_stuff = '_'}). 

Je veux une simple fonction qui ajoute un de ces enregistrements à une base de données de mnesia. Mais je veux qu'il échoue s'il y a déjà une entrée avec la même clé primaire .

(Dans les exemples suivants, supposons que je l'ai déjà défini

db_get_data(Key)-> 
    Q = qlc:q([Datum 
       || Datum = #data{primary_key = RecordKey} 
         <- mnesia:table(data), 
        RecordKey =:= Key]), 
    qlc:e(Q). 

)

Les travaux suivants, mais qui me frappe comme une sorte de laid ...

add_data(D) when is_record(D, data)-> 
    {atomic, Result} = mnesia:transaction(fun()-> 
                case db_get_data(D#data.primary_key) of 
                 [] -> db_add_data(D); 
                 _ -> {error, bzzt_duplicate_primary_key} 
                end 
              end), 

    case Result of 
     {error, _} = Error -> throw(Error); 
     _ -> result 
    end. 

Cette fonctionne aussi, mais est également moche:

add_data(D) when is_record(D, data)-> 
    {atomic, Result} = mnesia:transaction(fun()-> 
                case db_get_data(D#data.primary_key) of 
                 [] -> db_add_data(D); 
                 _ -> throw({error, bzzt_duplicate_primary_key}) 
                end 
              end). 

Il diffère de ce qui précède en ce que le jette au-dessus

{error, bzzt_duplicate_primary_key}, 

alors que celui-ci jette

{error, {badmatch, {aborted, {throw,{error, bzzt_duplicate_primary_key}}}}} 

donc: est-il une convention pour indiquer ce genre d'erreur? Ou y a-t-il une manière intégrée que je peux obtenir la Mnesia pour lancer cette erreur pour moi?

Répondre

3

Je pense que les deux sont très bien, si vous ne faites que votre code plus jolie, comme:

add_data(D) when is_record(D, data)-> 

    Fun = fun() -> 
        case db_get_data(D#data.primary_key) of 
         [] -> db_add_data(D); 
         _ -> throw({error, bzzt_duplicate_primary_key}) 
        end 
      end, 

    {atomic, Result} = mnesia:activity(transaction, Fun). 

ou

add_data(D) when is_record(D, data)-> 

    Fun = fun() -> 
        case db_get_data(D#data.primary_key) of 
         [] -> db_add_data(D); 
         _ -> {error, bzzt_duplicate_primary_key} 
        end 
      end, 

    {atomic, Result} = mnesia:activity(transaction, Fun), 

    case Result of 
     {error, Error} -> throw(Error); 
     _    -> result 
    end. 

jetez-vous des erreurs ou retourner des erreurs? Je retournerais une erreur moi-même. Nous divisons le code en unités de travail mnesia - un module avec un ensemble de fonctions qui effectuent des activités de base de mnésie non dans les transactions, et un module api qui «compose» les unités de travail en transactions mnesia avec des fonctions très similaires à celles ci-dessus .

+0

Erlang est la langue dans laquelle je pense que les erreurs retournées fonctionnent réellement. La correspondance de modèle et Fail Fast aident réellement à ce que les erreurs retournées fassent ce que vous voulez dire, au lieu de se perdre quelque part sur la ligne. –

+0

Je suis d'accord personnellement - nous avons tendance à ne lancer que des erreurs lors de l'analyse de l'entrée de l'utilisateur ou d'autres circonstances où un lancer représente un «retour à ici de nombreux endroits différents» et nous allons trier ... –

Questions connexes