Ho bisogno di un approccio al problema di prevenire l'inserimento di record duplicati nel database

2

Un servizio web che chiamo restituisce un elenco di dati. I dati dal webservice vengono aggiornati periodicamente, quindi una chiamata al servizio web eseguita in un'ora potrebbe restituire gli stessi dati di una chiamata effettuata in un'ora. Inoltre, i dati vengono restituiti in base a una data di inizio e di fine.

Abbiamo più utenti che possono eseguire la ricerca del servizio web e è probabile che i dati duplicati vengano restituiti (in particolare per i dati storici). Tuttavia non voglio inserire questi dati duplicati nel database.

Ho creato una tabella db in cui sono archiviati i dati (le colonne più importanti sono)

Id int autoincrement PK  
Date date not null        --The date to which the data set belongs.  
LastUpdate date not null  --The date the data set was last updated.  
UserName varchar(50)      --The name of the user doing the search.

Uso SQL Server 2008 Express con C # 4.0 e Visual Studio 2010. Entity Framework viene utilizzato come ORM. Se le procedure memorizzate potrebbero essere evitate nella soluzione proposta, allora questo sarà un vantaggio.

Un altro modo di interpretare ciò che sto chiedendo una soluzione è il seguente: Ho un milione di record unici nel mio tavolo. Un utente fa una nuova ricerca. I risultati della ricerca dell'utente contengono circa 300k di record dei dati già presenti nel db. È necessaria una soluzione efficiente per trovare e inserire solo i record univoci.

Una combinazione di Date , LastUpdate e UserName rende un record univoco.

    
posta Eminem 04.07.2012 - 07:54
fonte

8 risposte

0

Ho scelto la seguente soluzione.
Sulla mia tabella sql server, ho aggiunto un indice. Controlla l'immagine per le impostazioni

InVisualStudio,hoaggiornatoilmioeddmx(fileframeworkEntity),maquandohoprovatoainserireirecordduplicati,tuttoquellochehoottenutoèstatounaltroerrore:

System.Data.Entity.Infrastructure.DbUpdateConcurrencyException:Storeupdate,insert,ordeletestatementaffectedanunexpectednumberofrows(0).Entitiesmayhavebeenmodifiedordeletedsinceentitieswereloaded.RefreshObjectStateManagerentries.

Quindihocreatounasemplicestoredprocedureperaggiornarel'entità.Aggiuntalastoredprocedurealmiofileedmxechiamatadalmiocodiceelecosestannofunzionandoadessoeiduplicatisonoignorati.

eccounlinkchemihaaiutatoatrovareunasoluzione
link
link

    
risposta data 04.07.2012 - 15:50
fonte
5

Bene, la soluzione ovvia è avere una chiave univoca sulle colonne che rendono la riga univoca.

A combination of the Date, LastUpdate and UserName makes a record unique.

In alternativa, potresti semplicemente sbarazzarti della chiave surrogata e usare la chiave primaria sopra riportata (dipende da dove la stai usando).

Gli inserti dovrebbero essere fatti usando Unisci , che ti consente di inserire il record solo quando non esiste già.

    
risposta data 04.07.2012 - 18:36
fonte
4

Devi scoprire quali record di colonne rendono unici. Quindi di solito si imposta un vincolo univoco su una / più colonne nel database. Questo (a seconda del sistema db) genererà qualche errore se vuoi inserire un altro record con le stesse colonne univoche.

Vedi link

    
risposta data 04.07.2012 - 08:28
fonte
2

Un altro approccio: aggiungi una colonna al tuo database, "Hash". È un SHA-256 o qualcosa di simile - qualcosa abbastanza grande per essere unico. Richiedi che la colonna sia unica.

    
risposta data 05.07.2012 - 02:32
fonte
1

Prova questo:

IF (SELECT TOP(1) text FROM the_table WHERE text='yourtext') <> 'yourtext'
begin
 INSERT INTO the_table (text) VALUES ('yourtext')
end

interroga il DB per il testo e lo seleziona, se trova una riga, non si attiva, se non trova una riga, verrà inserito.

Non è ancora ben testato.

    
risposta data 04.07.2012 - 10:20
fonte
0

Una soluzione semplice sarebbe quella di creare una cache in memoria supportata da un set, che dovrebbe scrivere le informazioni nel database, solo quando è pieno, e dire solo 10000 voci lasciando spazio per altri 10000 (vedilo come una coda ). O memorizzarlo nel DB quando la chiamata WS restituisce dati diversi (a condizione che dati diversi nelle chiamate significano che non ci sono duplicati in esso). Usando un set, hai la certezza che non ci sono duplicati in esso.

    
risposta data 04.07.2012 - 08:08
fonte
0

Il tuo cliente potrebbe tenere traccia delle righe modificate (create / aggiornate / cancellate) e invia solo quelle modificate al server. Con una chiave univoca definita, puoi eseguire inserimenti per le righe identificate dal tuo cliente come nuovo. In questo modo, devi solo inviare le righe modificate (create / aggiornate / cancellate) al database. Non è necessario inviare l'intero set di dati recuperato se non è stato modificato. Questo tipo di elaborazione è disponibile in EF tramite le classi ObjectContext, ObjectStateManager.

    
risposta data 04.07.2012 - 09:55
fonte
0

Facile,

  1. Crea un nome o un numero univoco per ogni client che accede a db ws.
  2. Creare una tabella denominata "scaricata" e inserire una riga ogni volta che un client accede a ws e recupera le righe dal database. Questa riga conterrà il nome del client e l'ID univoco della riga della tabella principale
  3. La prossima volta che accedi ai ws per i dati, modifica la selezione da includere come o join, solo le righe che non sono state "scaricate" da questo utente.

Capito?

    
risposta data 05.07.2012 - 00:26
fonte

Leggi altre domande sui tag