Dove memorizzare le traduzioni per i valori nei testi di visualizzazione corrispondenti?

1

Questa è probabilmente una domanda ingenua, ma sto cercando di capire le best practice del settore per lavorare con numeri magici e i relativi testi di visualizzazione. Ad esempio, se una transazione è debito o credito potrebbe essere memorizzata come un campo di bit nel database, ma il vero / falso / 0/1 deve essere visualizzato come "Debito" o "Credito" ecc. In genere, ci sarebbe un enum che deve essere mantenuto sincronizzato con i numeri magici e il loro significato.

Ci sono due casi specifici che sto cercando di risolvere -

  1. Vogliamo tradurli in testo leggibile dall'uomo - L'interfaccia utente deve sapere che quando vede zero, deve visualizzare "Debit" ecc.

  2. Vogliamo lavorare con i numeri magici all'interno del codice sorgente - Qui di solito li traduciamo come enumerazioni. Gli Enum si liberano dei numeri magici ma sono così difficili da mantenere sincronizzati con i valori del database.

In un'applicazione di dimensioni moderate, possiamo finire con centinaia o migliaia di tali traduzioni, ad esempio -

Contesto - {Valore, traduzione}

TransactionType - {0, Debit}, {1, Credit}

FileType - {0, CSV}, {1, XML}, {2, Excel}

ItemType - {0, Manual}, {1, Automated}, {2, Writeoff}, {3, System}

Stato - {0, Attivo}, {1, InActive}, {2, In attesa}, {3, Consegnato} ecc. ecc.

Non riesco a capire una soluzione che permetta di sincronizzare / caricare le enumerazioni dinamicamente dal database E permette di tradurre i valori del database in testo senza perdere l'integrità referenziale.

Vedo le seguenti opzioni -

  1. Hardcoding nell'interfaccia utente (visualizzazioni o tramite metodi GetDisplayTextFor (int), ecc.)
  2. Alcuni file di testo / XML esterni
  3. Una tabella di database con colonne (Contesto, Valore, Traduzione) - Ma ora abbiamo creato nuovi numeri magici nella colonna "Contesto".
  4. Tabelle di database per ogni set di tali mapping con valori che fanno riferimento a chiavi esterne - Ciò consentirà l'integrità referenziale ma implicherà l'aggiunta di tabelle potenzialmente numerose.

Quali sono le pratiche del settore per questo problema? Le enum possono essere generate dinamicamente dal database e possono essere convertite in testi o le enumerazioni dovrebbero essere evitate del tutto per tali casi? Qualsiasi altra soluzione / schema standard che risolva almeno il maggior numero possibile di problemi?

    
posta Achilles 14.01.2017 - 04:39
fonte

2 risposte

4

Dato che stai parlando in un contesto .NET, le traduzioni vengono solitamente archiviate in file di risorse. Ciò significa che creerai due risorse: TransactionTypeCredit e TransactionTypeDebit . Queste risorse sarebbero poi tradotte in inglese, cinese, russo, ecc.

Quelle risorse è ciò che userà l'interfaccia utente. Ma a differenza di quanto suggerisci nella tua domanda:

UI needs to know that when it sees zero, it needs to display "Debit"

l'interfaccia utente non dovrebbe mai vedere zero. O uno. O ventiquattro. Quelli sono i valori del database che dovrebbero rimanere nel database: l'interfaccia utente non dovrebbe essere a conoscenza di quei valori.

Ciò significa che nel livello aziendale, verranno create due classi: una per la transazione di tipo credito e un'altra per la transazione di tipo debito. Sia CreditTransaction che DebitTransaction erediteranno da BusinessTransaction e contengono le regole aziendali corrispondenti ai rispettivi tipi di transazione.

Perché classi invece di enum ? Semplicemente perché sono abbastanza sicuro che le regole aziendali differiscono per una transazione di credito da una debito. Ciò significa che, se ti attacchi con un enum , finirai per fare un sacco di dichiarazioni switch . In queste situazioni, "sostituisci il condizionale con il polimorfismo" la tecnica di refactoring rende il tuo codice più gestibile.

Una volta che hai queste classi, l'interfaccia utente le visualizzerà in modo diverso, probabilmente indicando risorse diverse (che abbiamo creato sopra), ma forse anche personalizzando la presentazione come cambiare lo sfondo.

L'attività rimasta è quella di associare tali classi ai valori del database. Questo è l'obiettivo del livello di accesso ai dati. Se si utilizza un ORM, di solito è disponibile un'opzione che consente di creare classi diverse in base a un valore specifico di una colonna del database. In caso contrario, scrivere il proprio codice (eventualmente utilizzando uno schema di fabbrica). Questa factory dovrebbe essere l'unica posizione in cui avrai un'istruzione switch per i tipi di transazione (anche una mappa funzionerà).

Mantenerlo sincronizzato

I can't figure out a solution that allows enums to be synced/loaded dynamically from the database AND allows translations of database values to texts

Non puoi.

Prendendo il tuo esempio Status - {0, Active}, {1, InActive}, {2, Pending}, {3, Delivered} , immagina di averli implementati con una soluzione magica che genera automaticamente il codice per te.

Ora, vuoi aggiungere il quinto stato: annullato. Lo fai nel database, e un ORM molto intelligente passa attraverso i vincoli del database e crea uno stato aggiuntivo nel codice. Primo problema: in che modo l'ORM indovina come nominare questo stato, dato che il database dice solo che invece di 0..3, ora accetta 0..4?

Immaginiamo di averlo capito e, magicamente, l'ORM indovina che il quinto stato corrisponde a Cancelled . Alcuni altri strumenti generano automaticamente la risorsa corrispondente e influiscono anche sul valore "Cancellato" per la sua cultura en-US. Ora cosa? Come lo tradurrebbe in ebraico, tedesco o giapponese?

Una nota su enum s

Sembra che tu abbia gradito enum s, dato il numero di volte che li hai citati nella tua domanda. Tuttavia, dovresti evitare di usarli come scelta predefinita per tutto . Una regola generale è che se hai una collezione di elementi che potrebbero essere estesi in futuro, enum s è una buona scelta. In caso contrario, attenersi alle costanti. Se disponi di regole aziendali diverse a seconda dell'elemento della raccolta, utilizza l'ereditarietà per evitare le dichiarazioni di switch .

    
risposta data 14.01.2017 - 09:33
fonte
2

L'uso delle enumerazioni di solito aiuta a mantenere il controllo sull'uso del codice, ma in genere limito le enum ai valori controllati dalle applicazioni e non mi aspetto di cambiare con qualsiasi livello di frequenza. i valori di cui parli sembrano essere in grado di cambiare abbastanza o di creare nuovi set di valori a volte. usare le enumerazioni per questo scenario sarebbe ingombrante. opterei per un modello di dati basato su database per gestire questi elementi, che di solito considero una sorta di "mappatura".

la memorizzazione di questi dati in tabelle risolve il problema dell'integrità dei dati e può essere eseguita senza la necessità di creare costantemente nuove tabelle, utilizzando un progetto di tabella autoreferenziale.

link

Aggiornamento (17/01/2017):

Con l'approccio della tabella di mappatura, la sincronizzazione è praticamente "integrata", purché si utilizzi una forma di ORM all'interno del livello dati.

Ecco alcuni esempi di codice rapidi e sporchi, supponendo che tu stia utilizzando EntityFramework:

public class Trade
{
    public int Id {get; set; }
    public string Description {get; set; }
    public decimal Amount {get; set; }
    public int TransactionTypeId {get; set; }

    [ForeignKey("TransactionTypeId")
    public DataTypeMap TransactionType {get; set; }
}

public class DataTypeMap
{
    public int Id {get; set; }
    public string Name {get; set; }
    public string DisplayName {get; set; }
    public int ParentId {get; set; }

    [ForeignKey("TransactionTypeId")
    public DataTypeMap ParentMap {get; set; }
}

Con questi due modelli, EF, estrarrà le informazioni necessarie dalla tabella correlata (Proprietà di navigazione), quindi finché Trade.TransactionTypeId avrà il valore intero corretto, è possibile ottenere il testo visualizzato facendo riferimento a Trade.TransactionType. DisplayName.

Naturalmente, c'è ancora la codifica della modalità da fare per collegare tutto sul lato EF, ma è praticamente roba standard EF.

    
risposta data 16.01.2017 - 17:06
fonte

Leggi altre domande sui tag