# Primary key: Doc ID o Codice?

**URL:** <https://community.instantdeveloper.com/t/primary-key-doc-id-o-codice/54>\
**Category:** Non categorizzato\
**Tags:** database, idf\
**Created:** [6 Luglio 2021, 7:23am UTC](https://community.instantdeveloper.com/t/primary-key-doc-id-o-codice/54 "2021-07-06T07:23:53Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![r.bianco](https://community.instantdeveloper.com/user_avatar/community.instantdeveloper.com/r.bianco/32/41_2.png) [@r.bianco](https://community.instantdeveloper.com/u/r.bianco)\
**Post date:** [6 Luglio 2021, 7:23am UTC](https://community.instantdeveloper.com/t/primary-key-doc-id-o-codice/54/1 "2021-07-06T07:23:53Z")

</div>

Nella progettazione della struttura di un DB, una delle scelte da effettuare è quella della definizione della PK.

**DOC ID**  
Volendo trattare i dati attraverso Classi DO, InDe mette a disposizione diversi servizi, come:

- Identificazione documenti
- Allegati
- Sincronizzazione
- ecc…

Alcuni di questi richiedono espressamente che la PK sia definita come _DocID_ (Identificazione documentale), in altri non è strettamente necessario ma la scelta del DocID facilita grandemente l’utilizzo del servizio (Sincronizzazione).

**CODICE**  
D’altra parte, in molti ambiti, l’operatore è abituato a trattare gli elementi che manipola tramite _Codice_ (codice articolo, codice cliente…).  
Pensiamo all’imputazione rapida di un DDT, in cui l’operatore smaliziato conosce la maggior parte dei codici più utilizzati ed è abituato a riferirsi ad essi. Eliminare il codice e costringerlo a imputare i dati tramite una ricerca per descrizione diventa pressoché inaccettabile.

**Quale scelta effettuare?**  
Nel nostro ultimo progetto abbiamo scelto una _soluzione mista_:

- Tabelle come Iva, Province, Operatori: _Codice_
- Tabelle come Clienti, Articoli: _DocID + Codice_

L’idea è riuscire ad avere il meglio delle due soluzioni.  
Nella soluzione _Codice_ è stata valutata una bassa probabilità di modifica del codice e un basso vantaggio nell’utilizzo del DocID.  
Nella soluzione _DocID + Codice_ abbiamo la che la PK è formata dal solo DocID, avendo poi un indice univoco per Codice. In questo caso, la valutazione è stata l’opposto della precedente: una più alta probabilità di modifica del codice e dell’utilizzo dei servizi documentali.

Così facendo, l’operatore ha la possibilità di lavorare riferendosi sempre tramite Codice, mentre il DocID mi permette di alleggerire il lavoro negli ambiti in cui è richiesto.  
Non contenti, in alcune tabelle (per fortuna poche), abbiamo sia il DocID che il Codice, per facilitare le query effettuate al di fuori dell’applicazione.

**Conclusioni**  
Finora questa soluzione ha portato ad _accontentare un po’ tutti_ e non ha creato grossi problemi.  
Eppure non mi convince del tutto 😑.

_Voi cosa ne pensate?_  
_Quali soluzioni adottate?_

---

<div class="post-metadata">

**Author:** ![paolo.giannelli](https://community.instantdeveloper.com/user_avatar/community.instantdeveloper.com/paolo.giannelli/32/12_2.png) [@paolo.giannelli](https://community.instantdeveloper.com/u/paolo.giannelli)\
**Post date:** [6 Luglio 2021, 10:28am UTC](https://community.instantdeveloper.com/t/primary-key-doc-id-o-codice/54/2 "2021-07-06T10:28:06Z")

</div>

Grazie @r.bianco concordo con la tua esperienza e da formatore ho visto questo utilizzo delle PK diverse volte durante le sessioni di formazione con i nuovi utenti di Instant Developer Foundation.

---

<div class="post-metadata">

**Author:** ![giorba](https://community.instantdeveloper.com/user_avatar/community.instantdeveloper.com/giorba/32/582_2.png) [@giorba](https://community.instantdeveloper.com/u/giorba)\
**Post date:** [6 Luglio 2021, 10:19pm UTC](https://community.instantdeveloper.com/t/primary-key-doc-id-o-codice/54/3 "2021-07-06T22:19:10Z")

</div>

Personalmente, ormai affido tutte le chiavi primarie al DocID (UUID in IDC) e indicizzo in maniera opportuna i campi tipo Codice, quando ce ne sono, relegandone l’uso alla sola interfaccia per semplificare la ricerca agli utenti. Il vantaggio di adottare una sola metodologia senza dovermi ricordare dove per la PK ho usato un campo piuttosto che un altro per me vince sugli altri, tenuto anche conto che IDC è in grado di compilare automaticamente le query corrette pure nel caso di documenti collegati tra loro. Tirate le somme, come ho detto per me questo è il sistema più pratico in ogni scenario.

---

<div class="post-metadata">

**Author:** ![f.faleschini](https://community.instantdeveloper.com/letter_avatar_proxy/v4/letter/f/a9adbd/32.png) [@f.faleschini](https://community.instantdeveloper.com/u/f.faleschini)\
**Post date:** [20 Luglio 2021, 10:12am UTC](https://community.instantdeveloper.com/t/primary-key-doc-id-o-codice/54/4 "2021-07-20T10:12:28Z")

</div>

Ciao. Noi usiamo docId per tutto, anche se un esperienze precedenti (prima di adottare foundation) usavamo solo PK intere contatori (anche se gestite a mano e non con identity).

Usando docId si delega in qualche modo a foundation il problema delle PK, di certo quando si scrive una query a mano scrivere “where ID= ''f4\_:kò?()\_çòasjiwjì?” è spiacevole, però a livello di PK, per integrità referenziale un docId è ottimo e poi anche per la sincronizzazione è ineccepibile.

---

<div class="post-metadata">

**Author:** ![r.bianco](https://community.instantdeveloper.com/user_avatar/community.instantdeveloper.com/r.bianco/32/41_2.png) [@r.bianco](https://community.instantdeveloper.com/u/r.bianco)\
**Post date:** [20 Luglio 2021, 10:24am UTC](https://community.instantdeveloper.com/t/primary-key-doc-id-o-codice/54/5 "2021-07-20T10:24:28Z")

</div>

Non usate mai codici per identificare un elemento? Il classico codice articolo per esempio. Come vi approcciate a questo?

---

<div class="post-metadata">

**Author:** ![f.faleschini](https://community.instantdeveloper.com/letter_avatar_proxy/v4/letter/f/a9adbd/32.png) [@f.faleschini](https://community.instantdeveloper.com/u/f.faleschini)\
**Post date:** [20 Luglio 2021, 4:58pm UTC](https://community.instantdeveloper.com/t/primary-key-doc-id-o-codice/54/6 "2021-07-20T16:58:18Z")

</div>

Sì, usiamo codici ma non li mettiamo nella PK, ne validiamo l’unicità nell’OnValidate. Non c’è un conrollo a livello DB ma solo applicativo, quindi bug a parte per l’utente è una sensazione simile ad avere la PK codice. Ciao.

---

<div class="post-metadata">

**Author:** ![paolo.giannelli](https://community.instantdeveloper.com/user_avatar/community.instantdeveloper.com/paolo.giannelli/32/12_2.png) [@paolo.giannelli](https://community.instantdeveloper.com/u/paolo.giannelli)\
**Post date:** [21 Luglio 2021, 6:47am UTC](https://community.instantdeveloper.com/t/primary-key-doc-id-o-codice/54/7 "2021-07-21T06:47:52Z")

</div>

Utilizzando un codice univoco che non sia la PK della tabella di solito io metto nel database un indice unique per quel codice così anche inserimenti fatti direttamente dal manager de database non mi creano duplicati.

---

<div class="post-metadata">

**Author:** ![f.faleschini](https://community.instantdeveloper.com/letter_avatar_proxy/v4/letter/f/a9adbd/32.png) [@f.faleschini](https://community.instantdeveloper.com/u/f.faleschini)\
**Post date:** [21 Luglio 2021, 8:59am UTC](https://community.instantdeveloper.com/t/primary-key-doc-id-o-codice/54/8 "2021-07-21T08:59:04Z")

</div>

Buona considerazione, in effetti pensare che la validazione DO sia a prova di bomba è una leggerezza: l’indice dul DB ci tutela da tutte le operazioni “a picconate”. Ciao!

---

<div class="post-metadata">

**Author:** ![r.bianco](https://community.instantdeveloper.com/user_avatar/community.instantdeveloper.com/r.bianco/32/41_2.png) [@r.bianco](https://community.instantdeveloper.com/u/r.bianco)\
**Post date:** [21 Luglio 2021, 9:44am UTC](https://community.instantdeveloper.com/t/primary-key-doc-id-o-codice/54/9 "2021-07-21T09:44:53Z")

</div>

> [@paolo.giannelli](#):
>
> Utilizzando un codice univoco che non sia la PK della tabella di solito io metto nel database un indice unique per quel codice così anche inserimenti fatti direttamente dal manager de database non mi creano duplicati.

Esatto. Inoltre l’indice velocizza le qry basate su codice.

---

<div class="post-metadata">

**Author:** ![stefano.masiero](https://community.instantdeveloper.com/user_avatar/community.instantdeveloper.com/stefano.masiero/32/184_2.png) [@stefano.masiero](https://community.instantdeveloper.com/u/stefano.masiero)\
**Post date:** [10 Settembre 2021, 9:35am UTC](https://community.instantdeveloper.com/t/primary-key-doc-id-o-codice/54/10 "2021-09-10T09:35:56Z")

</div>

Ciao  
come regola generale nella progettazione di un database tendo sempre a definire una PK tecnica (docid o sequence) che non ha legami con l’informazione contenuta nella tabella per i seguenti motivi:

- Responsabilità: la PK mi serve per definire vincoli relazionali tra le tabelle, se devo identificare univocamente un record in base ai suoi dati informativi definisco una o più “chiavi logiche” (indice unique). Nel tempo la chiave logica potrebbe cambiare (contenuto o campi coinvolti) ed è buona cosa a livello di manutenzione non aver propagato tale codice nelle tabelle collegate.

- Performance: quando viene usata la PK per l’accesso a delle righe sia direttamente (filtro nella where specificando il valore) sia indirettamente (tramite clausola di join) alcuni dbms sono più veloci con certi tipi di dato piuttosto che con altri. Sapere di poter modificare il tipo di chiave in funzione della situazione mi dà più flessibilità rispetto alla scelta di un codice il cui tipo non è modificabile.

All’inizio avevo un po’ di remore ad utilizzare il docid di INDE ma adesso è la mia scelta di default e rispetto ai sequence ci sta aiutando a gestire situazioni particolari ad esempio portare dati da produzione a test senza problemi di gestione di chiavi diverse o duplicate (non mi dilungo, se qualcuno è interessato posso spiegare meglio cosa intendo).

---

<div class="post-metadata">

**Author:** ![r.bianco](https://community.instantdeveloper.com/user_avatar/community.instantdeveloper.com/r.bianco/32/41_2.png) [@r.bianco](https://community.instantdeveloper.com/u/r.bianco)\
**Post date:** [10 Settembre 2021, 10:33am UTC](https://community.instantdeveloper.com/t/primary-key-doc-id-o-codice/54/11 "2021-09-10T10:33:48Z")

</div>

Grazie mille, e benvenuto.  
Quindi, ad esempio, nelle righe dell’ordine non metterai il codice articolo ma il suo docid. Corretto?  
C’è qualche caso in cui, oltre al docid metteresti anche il codice?

---

<div class="post-metadata">

**Author:** ![stefano.masiero](https://community.instantdeveloper.com/user_avatar/community.instantdeveloper.com/stefano.masiero/32/184_2.png) [@stefano.masiero](https://community.instantdeveloper.com/u/stefano.masiero)\
**Post date:** [10 Settembre 2021, 12:55pm UTC](https://community.instantdeveloper.com/t/primary-key-doc-id-o-codice/54/12 "2021-09-10T12:55:35Z")

</div>

Grazie del benvenuto!  
Si esatto nell’ordine metterei solo il docid e non il codice.  
Non metto mai il codice nella tabella mentre nella classe documentale quasi sempre, ed è una funzionalità di inde che apprezzo molto, modificando la master query e mettendo in join le tabelle da cui voglio estrarre informazioni “derivate” mappandole su campi creati ad hoc.

---

<div class="post-metadata">

**Author:** ![Giancarlo](https://community.instantdeveloper.com/user_avatar/community.instantdeveloper.com/giancarlo/32/98_2.png) [@Giancarlo](https://community.instantdeveloper.com/u/Giancarlo)\
**Post date:** [10 Ottobre 2022, 3:36pm UTC](https://community.instantdeveloper.com/t/primary-key-doc-id-o-codice/54/13 "2022-10-10T15:36:57Z")

</div>

Ciao a tutti.

Volevo riprendere l’argomento in quanto anche noi all’inizio abbiamo avuto un po’ di perplessità su come approcciare il problema.  
Premetto che abbiamo il 99% delle soluzioni senza device mobile (per ora) per cui il problema della sincronizzazione non è molto sentito.  
Inizialmente e per il progetto SMART (il nostro nuovo ERP) abbiamo adottato l’utilizzo del ID di SQL progressivo contatore, ma nei nuovi progetti adotteremo il DocID di INDE.  
Questa doppia scelta è stata dettata dalle necessità.  
La gestione di SMART (il nostro ERP in Saas) nasce da un progetto inizialmente sviluppato con CodeOnTime, dove le relazioni sono per ID (contatore SQL), per cui abbiamo ereditato lo schema del DB completo con tutte le relazioni sull’ID, e cambiare lo schema, stored procedure e funzioni SQL era un lavoraccio, nonché il fatto che alcune parti del SW “vecchio” dovevano convivere su alcuni clienti.

C’è però un’altra “bega” che ci assilla e provo a spiegare meglio:  
INDE ha un problema noto e riconosciuto, che se sulle tabelle ci sono definiti dei trigger SQL (e noi ne usiamo parecchi), e se si estendono le entità di base con delle proprie classi derivate da ID\_DOCUMENT, nella propagazione delle proprietà si perde il valore dell’ultimo ID inserito in tabella, per cui si fa un macello quando si inseriscono i dati. Questo succede perché INDE per recuperare l’ultimo ID inserito usa lo variabile globale SQL **@@IDENTITY** anziché la funzione **SCOPE\_IDENTITY()**. La prima viene valorizzata con l’ultimo ID inserito nella sessione, mentre la seconda ritorna il valore dell’ultimo ID della tabella. Per ovviare al problema (vedi anche nel forum) si vanno a scrivere due righe di codice nell’evento after save della classe così da valorizzare l’ID correttamente, e se il trigger è su una sola tabella problemi non ce ne sono, ma iniziano quando le tabelle dell’entità sono più di una (4 o 5 come nel nostro caso…) perché l’evento after save viene notificato per tutte le classi dell’entità nello stesso momento, quindi l’ID che si recupera non è detto che sia quello della classe padre.  
Per farla breve il tutto si risolve utilizzando il DocID di INDE dove viene generato correttamente e propagato seguendo le relazioni delle PK.  
Resta il problema che non si può fare manutenzione “extra INDE” ad esempio da SQL manager o da un’altra applicazione scritta con un linguaggio diverso INDE.  
Per questo ci siamo scritti tre funzioni SQL per la generazione del DocID e la trasformazione del DocID in GUID e viceversa, così da poter fare in SQL quello che si fa in INDE…  
Di seguito lo script di generazione di una vista che serve all’interno delle funzioni, dal momento che in una funzione SQL non si può richiamare la funzione di sistema NEWID()

```
      CREATE view [dbo].[vw_NewGuid]
      as
      SELECT NEWID() AS NewGuid         
      GO

```

– =============================================  
– Author: MADA Service - Tamara Cocchi  
– Create date: 2022-08-11  
– Description: Funzione che converte un Doc ID di INDE in GUID  
– =============================================  
CREATE function [dbo].[DecodeDocID]  
(  
@DocId varchar(20)  
)  
returns varchar(36) as  
BEGIN

```
declare @guid varchar(36) = ''

declare @restoPrecedente as bigint = 0
	
DECLARE @Counter INT ,
		@giro int = 1,
		@moltiplicatore INT = 0,
		@guidTemp varchar(36)
		
SET @Counter=1
WHILE ( @Counter <= LEN(@DocId))
BEGIN
	set @restoPrecedente = 0
	
	declare @subGiro int = 1
	WHILE @subGiro <= 5
		BEGIN

			SELECT @moltiplicatore = CASE @subGiro
				WHEN 1
					THEN 1
				WHEN 2
					THEN 85
				WHEN 3
					THEN 7225
				WHEN 4
					THEN 614125
				ELSE
					52200625
			END

			declare @valore bigint 
			SET @valore = (CONVERT(varbinary,SUBSTRING(@docID,@counter,1))-40)*CONVERT(BIGINT,@moltiplicatore)+@restoPrecedente	
			set @restoPrecedente = @valore
			SET @Counter = @Counter + 1

			SET @subGiro = @subGiro + 1
		END
	
	SET @guidTemp = CONVERT(VARCHAR(1000), CONVERT(VARBINARY(4),CAST(@restoPrecedente AS BIGINT)),2)

	SET @guid = @guid + CASE @giro
							WHEN 1
								THEN @guidTemp + '-'
							WHEN 2
								THEN SUBSTRING(@guidTemp,5,4)+'-'+SUBSTRING(@guidTemp,1,4)+'-'
							WHEN 3
								THEN SUBSTRING(@guidTemp,7,2)+SUBSTRING(@guidTemp,5,2)+'-'+SUBSTRING(@guidTemp,3,2)+SUBSTRING(@guidTemp,1,2)
							ELSE
								SUBSTRING(@guidTemp,7,2)+SUBSTRING(@guidTemp,5,2)+SUBSTRING(@guidTemp,3,2)+SUBSTRING(@guidTemp,1,2)
						END
						
	SET @giro = @giro + 1
END

return @guid	

```

END

– =============================================  
– Author: MADA Service - Tamara Cocchi  
– Create date: 2022-08-11  
– Description: Funzione che converte un GUID in un Doc ID come INDE comanda  
– =============================================  
CREATE function [dbo].[EncodeDocID]  
(  
@guid varchar(36)  
)  
returns varchar(20) as  
BEGIN

```
declare @DocId varchar(20) = ''

declare @numero32bit as bigint
	
DECLARE @Counter INT ,
		@giro int = 1,
		@tentativi INT = 0,
		@divisore INT = 0,
		@docIDTemp varchar(20) = ''

SET	@guid = REPLACE(@guid,'-','') 

SET @Counter=1
WHILE ( @Counter <= LEN(@guid))
BEGIN
	declare @stringa varchar (50) = ''
	SELECT @stringa = CASE @giro
		WHEN 1
			THEN SUBSTRING(@guid,@counter,8)
		WHEN 2
			THEN SUBSTRING(@guid,@counter+4,4)+SUBSTRING(@guid,@counter,4)
		ELSE
			SUBSTRING(@guid,@counter+6,2)+SUBSTRING(@guid,@counter+4,2)+SUBSTRING(@guid,@counter+2,2)+SUBSTRING(@guid,@counter,2)
	END
	
	SELECT @numero32bit = CONVERT(bigint, convert(varbinary, '0x' + @stringa, 1))

	set @docIDTemp = ''
	declare @subGiro int = 1
	WHILE @subGiro <= 5
		BEGIN

			SELECT @divisore = CASE @subGiro
				WHEN 1
					THEN 52200625
				WHEN 2
					THEN 614125
				WHEN 3
					THEN 7225
				WHEN 4
					THEN 85
				ELSE
					1
			END

			declare @valore char 
			SET @valore = CHAR(@numero32bit / @divisore + 40)		
			select @docIDTemp = @valore + @docIDTemp
			set @numero32bit = @numero32bit % @divisore	

			SET @subGiro = @subGiro + 1
		END

	SET @docID = @docID + @docIDTemp

	SET @giro = @giro + 1
	SET @Counter = @Counter + 8
END

return @docID	

```

END

– =============================================  
– Author: MADA Service - Tamara Cocchi  
– Create date: 2022-08-11  
– Description: Funzione che crea un nuovo un Doc ID come INDE comanda  
– =============================================  
CREATE function [dbo].[GetNewDocID]  
()  
returns varchar(20) as  
BEGIN

```
declare @guid as varchar(36) = '',
		@DocId varchar(20) = ''

SELECT	@guid = NewGuid
FROM	[vw_NewGuid]

declare @numero32bit as bigint
	
DECLARE @Counter INT ,
		@giro int = 1,
		@trovato BIT = 0,
		@tentativi INT = 0,
		@divisore INT = 0,
		@docIDTemp varchar(20) = ''

WHILE @docID = '' and @tentativi < 100
	BEGIN

		SELECT @DocId = [dbo].[EncodeDocID](@guid)

		if CHARINDEX('\',@docID) > 0
			BEGIN
				SELECT	@guid = NewGuid
				FROM	[vw_NewGuid]
				set @docID = ''
			END

		set @tentativi = @tentativi + 1
	END

return @docID	

```

END

---

<div class="post-metadata">

**Author:** ![r.bianco](https://community.instantdeveloper.com/user_avatar/community.instantdeveloper.com/r.bianco/32/41_2.png) [@r.bianco](https://community.instantdeveloper.com/u/r.bianco)\
**Post date:** [10 Ottobre 2022, 4:16pm UTC](https://community.instantdeveloper.com/t/primary-key-doc-id-o-codice/54/14 "2022-10-10T16:16:20Z")

</div>

> [@Giancarlo](#):
>
> se sulle tabelle ci sono definiti dei trigger SQL (e noi ne usiamo parecchi), e se si estendono le entità di base con delle proprie classi derivate da ID\_DOCUMENT, nella propagazione delle proprietà si perde il valore dell’ultimo ID inserito in tabella

Ciao Giancarlo,  
a memoria, non siamo mai incappati in questa casistica (fortunatamente!).

Oltre questo, anche noi abbiamo usato le store procedure che traducono GIUD in DocID, per mantenere allineati il DB del gestionale fatto con InDe (A) e il DB del gestionale fatto con un altro sistema di sviluppo (B). In pratica, durante l’inserimento di un record da parte di B, chiamiamo una stored function che genera un nuovo GIUD e lo traduce in DocID, per poi popolare un campo apposito.  
Il record viene poi trasferito tramite WebAPI al gestionale A, e viene mantenuto allineato tramite questo campo.  
Con il senno di poi, però, non penso sia una buona idea perché abbiamo limitato B nel dialogo con altri applicativi, essendo il DocID proprio di InDe. Avrebbe avuto più senso mantenere nel DB di B un GIUD, per poi tradurlo in fase di ricezione/trasmissione via WebAPI.

---

<div class="post-metadata">

**Author:** ![Giancarlo](https://community.instantdeveloper.com/user_avatar/community.instantdeveloper.com/giancarlo/32/98_2.png) [@Giancarlo](https://community.instantdeveloper.com/u/Giancarlo)\
**Post date:** [10 Ottobre 2022, 4:40pm UTC](https://community.instantdeveloper.com/t/primary-key-doc-id-o-codice/54/15 "2022-10-10T16:40:04Z")

</div>

Ciao, r.bianco  
SI certo è giusta l’osservazione. In quest’ottica B potrebbe avere un GUID e non un DocID.  
Nel nostro caso però è il nostro DB che deve far coesistere anche Applicazioni non INDE, per cui è corretto (a mio avviso) generare ID come vuole INDE anche fuori da INDE.  
Non so se mi sono spiegato…  
Ciao…
