2010-09-03 10 views
6

mi sono imbattuto in un problema cercando di aggiornare un campo chiave esterna:Come aggiornare una chiave esterna in modo efficiente in LINQ a SQL/SQLMetal?

record.ForeignId = newId; 

bombarda con "Operazione non è valida a causa dello stato corrente dell'oggetto" a causa di codice SQLMetal che getta System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException().

io non ero il primo a colpire il problema:

LinqToSQL Error : Operation is not valid due to the current state of the object e http://social.msdn.microsoft.com/forums/en-US/linqtosql/thread/f9c4a01a-195a-4f2b-a1cb-e2fa06e28b25/ discuterne, tra gli altri.

La loro soluzione è questa:

record.Foreign = Database.Foreigns.Single(c => c.Id == newId); 

Questo, naturalmente provoca una ricerca DB Foreign solo per ottenere un oggetto che ha di nuovo l'Es so già! Quindi, come posso realizzare questo aggiornamento senza la query inutile (o le query se ho molti di questi FK)?

risposta

3

È possibile creare nuovamente un'istanza del genitore (con l'ID corretto), Attach nel datacontext come stato del record esistente, quindi assegnare la proprietà Parent dell'oggetto figlio.

Ecco po 'di codice:

int theId = 5; 
Parent p = new Parent() { Id = theId}; 
dc.Parents.Attach(p); 
child.Parent = p; 
+0

Non sapevo di Attach(), ma l'ho provato e ho ricevuto un errore di chiave duplicato: "Impossibile aggiungere un'entità con una chiave già in uso." Ha interrogato il DB per scoprirlo, o forse quel disco era semplicemente sospeso nel mio contesto di dati ...? –

+0

DataContext tiene traccia di tutti i record che ha caricato (per chiave primaria). Se ha caricato un genitore con Id = 5, non sarà possibile allegare un'altra istanza di Genitore con Id = 5. –

+0

E c'è un modo per vedere se uno è memorizzato nella cache e pescarlo fuori se lo fa? E in caso contrario gin uno nuovo come nella tua risposta? O forse dirgli di abbandonare quello che ha prima? O qualcosa per far funzionare questo schema? –

1

Non risolve il problema, ma un modo per ottenere parzialmente attorno al carico aggiuntivo è quello di verificare se il valore attuale è diverso da quello del nuovo valore. Se è diverso, dovrai sostenere la query. Qualcosa di simile -

if(obj.PropertyID != newValue){ 
    obj.Property = PropertyClass.Load(newValue) 
} 
0

Ho avuto lo stesso problema. Ho creato una soluzione rapida, probabilmente non la soluzione migliore (in quanto potrebbe influire sulle prestazioni), ma ha funzionato per me.

Nella mia soluzione ho una classe con il mio DataContext dichiarato a livello di classe, quindi posso usarlo ovunque.

Nella mia soluzione tutto ciò che volevo fare (simile a te) è stato modificato un ID del tipo di account per un ID di tipo di account diverso (nel database questi sono FK) per un utente.

Poiché DataContext era già stato caricato, non consentiva la modifica. Il lavoro intorno?

Ho creato una funzione in cui creo una nuova istanza di DataContext, eseguo la query LINQ, invio le modifiche e successivamente il DataContext.

Problemi correlati