none
Db multilingua RRS feed

  • Domanda

  • Ciao a tutti
    sto creado un db per un sito multilingua. Ho pensato di adottare questa soluzione:
    In una tabella metto tutti i campi che non hanno bisogno di traduzione
    tbProdotto: id colore status

    E in un altro tutti i campi che bisogna tradurre:
    tbProdotto_Lingua: id fk_padre lingua prodotto descrizione

    Ho due dubbi:
    1- metto i campi della lingua principale in tbProdotto e le altre lingue in tbProdotto_Lingua o tutte le lingue in tbProdotto_Lingua?
    2- per recuperare tutti i dati nelle varie lingue, quindi prodotto_it prodotto_en, devo eseguire una query con diversi join o ci sono altri modi più efficienti?

    Grazie mille

    giovedì 17 ottobre 2013 16:22

Risposte

  • Ciao,

    beh! qui ci sono diverse scuole di pensiero su come realizzare un Db mutilingua.

    Non mi sto a divulgare sull'argomento, ma sicuramente ti suggerisco:

    - Usa la tabella Prodotti come anagrafica pura

    - Mettere tutte le traduzioni in lingua in un'unica tabella (nel tuo caso Prodotti_Lingua)

    - Sicuramente andare in join su una o più tabelle al fine di recuperare i testi (qui puoi anche fare un Vista su SQL)

    Maurizio


    Maurizio Cinti:[MCT,MCSD,MCSD,MCPD]
    Blog:mauriziocinti.com
    Twitter:@mcinti78
    LinkedIn:it.linkedin.com/in/mauriziocinti

    • Contrassegnato come risposta SviPla lunedì 21 ottobre 2013 07:16
    venerdì 18 ottobre 2013 08:44
  • Ciao SviPla,

    concordo anche io in linea di principio con la soluzione di Maurizio, ti aggiungo alcune considerazioni per darti un'ulteriore spunto di riflessione.

    Come ha detto Alessandro, lasciare la tabella Prodotti senza il nome del prodotto rende ogni record poco "parlante". Inserirei quindi un campo Nome nella tabella Prodotti e gestirei la lingua di default al pari delle altre nella relativa tabella Prodotti_Lingua. Questo per avere una uniformità di gestione delle lingue. 

    La considerazione di Alessandro sulle lingue non di default richiede che tu faccia un minimo di analisi per capire qual'è la lingua che conviene usare di default. Se vuoi ridurre l'uso di un join e il tuo mercato è prevalentemente tedesco, conviene usare quella come lingua di default. E se poi il mercato cambia? ;-)

    C'è inoltre da tenere conto che la prima volta la lingua di default sarà il tedesco, ma dalla visita successiva potrebbe diventare per sempre l'italiano.  

    Per quanto riguarda la query prova a dare un'occhiata a questa soluzione che genera una tabella PIVOT.


    CREATE TABLE [tbProdotto](
    	[id] [int] IDENTITY(1,1) NOT NULL,
    	[nome] [varchar](50) NULL,
    	[colore] [varchar](50) NULL,
    	[status] [int] NULL,
     CONSTRAINT [PK_tbProdotto] PRIMARY KEY CLUSTERED 
    	(
    	[id] ASC
    	)
    )
    
    CREATE TABLE [tbProdotto_Lingua](
    	[id] [int] IDENTITY(1,1) NOT NULL,
    	[fk_padre] [int] NOT NULL,
    	[lingua] [varchar](10) NULL,
    	[prodotto] [varchar](50) NULL,
    	[descrizione] [varchar](1000) NULL,
     CONSTRAINT [PK_tbProdotto_Lingua] PRIMARY KEY CLUSTERED 
    	(
    	[id] ASC
    	)
    )
    
    ALTER TABLE [tbProdotto_Lingua]  
    WITH CHECK ADD  CONSTRAINT [FK_tbProdotto_Lingua_tbProdotto] FOREIGN KEY([fk_padre])
    REFERENCES [tbProdotto] ([id])
    ON DELETE CASCADE
    
    INSERT INTO [tbProdotto] ([Nome],[colore],[status]) VALUES ('Palla','Rosso',1)
    INSERT INTO [tbProdotto] ([Nome],[colore],[status]) VALUES ('Racchetta da tennis','Verde',1)
    INSERT INTO [tbProdotto] ([Nome],[colore],[status]) VALUES ('Racchetta da Ping pong','Giallo',2)
    INSERT INTO [tbProdotto] ([Nome],[colore],[status]) VALUES ('Mazza da baseball','Grigio',1)
    INSERT INTO [tbProdotto] ([Nome],[colore],[status]) VALUES ('Scarpe da calcio','Blu',3)
    
    INSERT INTO [tbProdotto_Lingua] ([fk_padre],[lingua],[prodotto],[descrizione])
         VALUES (1,'FR','Balle','Balle')
    INSERT INTO [tbProdotto_Lingua] ([fk_padre],[lingua],[prodotto],[descrizione])
         VALUES (1,'EN','Ball','Ball')
    INSERT INTO [tbProdotto_Lingua] ([fk_padre],[lingua],[prodotto],[descrizione])
         VALUES (2,'IT','Racchetta da tennis','Racchetta da tennis')
    INSERT INTO [tbProdotto_Lingua] ([fk_padre],[lingua],[prodotto],[descrizione])
         VALUES (2,'EN','Tennis racket','Tennis racket')
    INSERT INTO [tbProdotto_Lingua] ([fk_padre],[lingua],[prodotto],[descrizione])
         VALUES (1,'DE','Kugel','Kugel')
    
    SELECT id, Nome as [Prodotto],
        EN AS EN,
    	FR AS FR,
    	DE AS DE
    FROM
        (SELECT [tbProdotto].id, Nome, Lingua, Prodotto FROM [tbProdotto] INNER JOIN [tbProdotto_Lingua] 
    		ON [tbProdotto].id = [tbProdotto_Lingua].fk_padre)
        AS source
    PIVOT
    (
       MAX(Prodotto)
    FOR lingua IN ([EN], [FR], [DE])
    ) AS PivotTable

    In questo modo ottieni una tabella come questa

    

    Daniele


    • Modificato Daniele Cazzaro venerdì 18 ottobre 2013 13:40
    • Contrassegnato come risposta SviPla lunedì 21 ottobre 2013 07:18
    venerdì 18 ottobre 2013 13:27
  • Ciao,

    secondo me:

    1- segui l'indicazione di Maurizio e non sportace l'entità in generale

    2- non ci sono modi più efficienti di query set based su sql server :)

    detto questo, puoi pensare ad un default name che è il prodotto in sé, ovvero l'entità. Il nome di default mettilo pure nell'entità, anche se questo poi ti costringerà a fare una gestione del null con delle left join sulle traduzioni (utilizzando ad esempio COALESCE).

    Se le lingue "non di default" sono poco usate, il metodo del campo di default sull'entità ti può ridurre il peso della chiamata. Se invece ogni lingua ha sempre il medesimo peso, puoi anche pensare di mettere tutte le lingue fuori, tanto la join la fai sempre e comunque in quel caso.

    Diciamo che poi puoi pensare anche a strade alternative, ad esempio non usare sql server e segnarti solamente l'entità su database per poi fare lookup applicative contro una cache o un layer non necessariamente relazionale per le traduzioni. Questa è più una scelta architetturale e tecnologica.

    ciao


    Alessandro Alpi SQL Server MVP

    • Contrassegnato come risposta SviPla lunedì 21 ottobre 2013 07:16
    venerdì 18 ottobre 2013 13:12
    Moderatore

Tutte le risposte

  • Ciao,

    beh! qui ci sono diverse scuole di pensiero su come realizzare un Db mutilingua.

    Non mi sto a divulgare sull'argomento, ma sicuramente ti suggerisco:

    - Usa la tabella Prodotti come anagrafica pura

    - Mettere tutte le traduzioni in lingua in un'unica tabella (nel tuo caso Prodotti_Lingua)

    - Sicuramente andare in join su una o più tabelle al fine di recuperare i testi (qui puoi anche fare un Vista su SQL)

    Maurizio


    Maurizio Cinti:[MCT,MCSD,MCSD,MCPD]
    Blog:mauriziocinti.com
    Twitter:@mcinti78
    LinkedIn:it.linkedin.com/in/mauriziocinti

    • Contrassegnato come risposta SviPla lunedì 21 ottobre 2013 07:16
    venerdì 18 ottobre 2013 08:44
  • Ciao,

    secondo me:

    1- segui l'indicazione di Maurizio e non sportace l'entità in generale

    2- non ci sono modi più efficienti di query set based su sql server :)

    detto questo, puoi pensare ad un default name che è il prodotto in sé, ovvero l'entità. Il nome di default mettilo pure nell'entità, anche se questo poi ti costringerà a fare una gestione del null con delle left join sulle traduzioni (utilizzando ad esempio COALESCE).

    Se le lingue "non di default" sono poco usate, il metodo del campo di default sull'entità ti può ridurre il peso della chiamata. Se invece ogni lingua ha sempre il medesimo peso, puoi anche pensare di mettere tutte le lingue fuori, tanto la join la fai sempre e comunque in quel caso.

    Diciamo che poi puoi pensare anche a strade alternative, ad esempio non usare sql server e segnarti solamente l'entità su database per poi fare lookup applicative contro una cache o un layer non necessariamente relazionale per le traduzioni. Questa è più una scelta architetturale e tecnologica.

    ciao


    Alessandro Alpi SQL Server MVP

    • Contrassegnato come risposta SviPla lunedì 21 ottobre 2013 07:16
    venerdì 18 ottobre 2013 13:12
    Moderatore
  • Ciao SviPla,

    concordo anche io in linea di principio con la soluzione di Maurizio, ti aggiungo alcune considerazioni per darti un'ulteriore spunto di riflessione.

    Come ha detto Alessandro, lasciare la tabella Prodotti senza il nome del prodotto rende ogni record poco "parlante". Inserirei quindi un campo Nome nella tabella Prodotti e gestirei la lingua di default al pari delle altre nella relativa tabella Prodotti_Lingua. Questo per avere una uniformità di gestione delle lingue. 

    La considerazione di Alessandro sulle lingue non di default richiede che tu faccia un minimo di analisi per capire qual'è la lingua che conviene usare di default. Se vuoi ridurre l'uso di un join e il tuo mercato è prevalentemente tedesco, conviene usare quella come lingua di default. E se poi il mercato cambia? ;-)

    C'è inoltre da tenere conto che la prima volta la lingua di default sarà il tedesco, ma dalla visita successiva potrebbe diventare per sempre l'italiano.  

    Per quanto riguarda la query prova a dare un'occhiata a questa soluzione che genera una tabella PIVOT.


    CREATE TABLE [tbProdotto](
    	[id] [int] IDENTITY(1,1) NOT NULL,
    	[nome] [varchar](50) NULL,
    	[colore] [varchar](50) NULL,
    	[status] [int] NULL,
     CONSTRAINT [PK_tbProdotto] PRIMARY KEY CLUSTERED 
    	(
    	[id] ASC
    	)
    )
    
    CREATE TABLE [tbProdotto_Lingua](
    	[id] [int] IDENTITY(1,1) NOT NULL,
    	[fk_padre] [int] NOT NULL,
    	[lingua] [varchar](10) NULL,
    	[prodotto] [varchar](50) NULL,
    	[descrizione] [varchar](1000) NULL,
     CONSTRAINT [PK_tbProdotto_Lingua] PRIMARY KEY CLUSTERED 
    	(
    	[id] ASC
    	)
    )
    
    ALTER TABLE [tbProdotto_Lingua]  
    WITH CHECK ADD  CONSTRAINT [FK_tbProdotto_Lingua_tbProdotto] FOREIGN KEY([fk_padre])
    REFERENCES [tbProdotto] ([id])
    ON DELETE CASCADE
    
    INSERT INTO [tbProdotto] ([Nome],[colore],[status]) VALUES ('Palla','Rosso',1)
    INSERT INTO [tbProdotto] ([Nome],[colore],[status]) VALUES ('Racchetta da tennis','Verde',1)
    INSERT INTO [tbProdotto] ([Nome],[colore],[status]) VALUES ('Racchetta da Ping pong','Giallo',2)
    INSERT INTO [tbProdotto] ([Nome],[colore],[status]) VALUES ('Mazza da baseball','Grigio',1)
    INSERT INTO [tbProdotto] ([Nome],[colore],[status]) VALUES ('Scarpe da calcio','Blu',3)
    
    INSERT INTO [tbProdotto_Lingua] ([fk_padre],[lingua],[prodotto],[descrizione])
         VALUES (1,'FR','Balle','Balle')
    INSERT INTO [tbProdotto_Lingua] ([fk_padre],[lingua],[prodotto],[descrizione])
         VALUES (1,'EN','Ball','Ball')
    INSERT INTO [tbProdotto_Lingua] ([fk_padre],[lingua],[prodotto],[descrizione])
         VALUES (2,'IT','Racchetta da tennis','Racchetta da tennis')
    INSERT INTO [tbProdotto_Lingua] ([fk_padre],[lingua],[prodotto],[descrizione])
         VALUES (2,'EN','Tennis racket','Tennis racket')
    INSERT INTO [tbProdotto_Lingua] ([fk_padre],[lingua],[prodotto],[descrizione])
         VALUES (1,'DE','Kugel','Kugel')
    
    SELECT id, Nome as [Prodotto],
        EN AS EN,
    	FR AS FR,
    	DE AS DE
    FROM
        (SELECT [tbProdotto].id, Nome, Lingua, Prodotto FROM [tbProdotto] INNER JOIN [tbProdotto_Lingua] 
    		ON [tbProdotto].id = [tbProdotto_Lingua].fk_padre)
        AS source
    PIVOT
    (
       MAX(Prodotto)
    FOR lingua IN ([EN], [FR], [DE])
    ) AS PivotTable

    In questo modo ottieni una tabella come questa

    

    Daniele


    • Modificato Daniele Cazzaro venerdì 18 ottobre 2013 13:40
    • Contrassegnato come risposta SviPla lunedì 21 ottobre 2013 07:18
    venerdì 18 ottobre 2013 13:27