La prima cosa che devi decidere è se pensi che sia importante distinguere (almeno in alcuni casi) tra stringhe vuote e NULL nel tuo livello aziendale (BL), oppure no. Ho visto sistemi in cui questa differenza era importante e altri sistemi in cui l'intero DB o la sua API erano configurati per non distinguere tra quei casi, perché nel BL non faceva differenza. Quindi, prima di chiedere su quale livello deve aver luogo una mappatura, chiarisci cosa vuoi usare qui.
Se è necessario distinguere NULL / undef dalla stringa vuota nel BL, la risposta è semplice: non eseguire alcuna sostituzione automatica. Mappare la stringa vuota su una stringa vuota e "undef" su NULL (e viceversa). Devi scrivere il tuo codice aziendale in modo che possa gestire correttamente anche stringhe vuote e valori "undef".
Se vuoi trattare "undef" e "stringa vuota" come uguali nella tua BL per tutte le tabelle e gli attributi, allora ha chiaramente senso lasciare che l'ORM faccia la mappatura. Se, tuttavia, lo si desidera solo qualche volta, per alcune colonne e in altri casi è necessario distinguere tra entrambi i valori, è necessario conoscere la frequenza con cui ci si aspetta questa situazione. Se il primo è una situazione rara, è necessario solo per circa una mezza dozzina di attributi, è possibile implementare il comportamento nel BL in base al "caso". Se hai 100 o più attributi per i quali "undef" e "stringa vuota" dovrebbero essere trattati come uguali, devi estendere il tuo ORM per lasciarlo gestire per certe colonne in modo generico.
Ad esempio: per determinate colonne con tag specifici, l'ORM potrebbe mappare qualsiasi valore NULL su una stringa vuota quando legge i dati dal DB e riconvertire la stringa vuota su NULL quando scrive di nuovo i dati. Estendere il tuo ORM in questo modo per fornire un mechnanism generico richiederà probabilmente un certo sforzo e devi decidere se riutilizzare questo meccanismo abbastanza spesso per trarne maggiori benefici rispetto allo sforzo necessario per implementarlo.