5

Ho un problema complesso in cui vorrei utilizzare la riflessione sul mio mapping di Entity Framework per trovare tutte le chiavi esterne che fanno riferimento a una tabella e voglio i nomi delle colonne quelle sono le chiavi estranee.Entity Framework - Riflessione su chiavi esterne e relazioni/associazioni

In base a another post on SO, posso facilmente trovare le proprietà di navigazione su una tabella tramite riflessione. Ma questo non mi da il nome della proprietà o della colonna che contiene il valore della chiave esterna.

Il motivo per cui sto provando a farlo è che ho un gran numero di tabelle (quasi 40) che fanno riferimento a una tabella di elementi. Diciamo che un utente immette un nuovo valore nella tabella degli articoli chiamata "Andew" e in seguito un amministratore nota che in realtà è solo un errore di battitura per l'elemento "Andrew" già esistente. Ora voglio trovare tutti i riferimenti a "Andew" e modificare tali riferimenti in "Andrew". Preferirei farlo in modo efficiente, quindi usare le proprietà di navigazione inversa sarebbe troppo lento dato che devi caricare i valori prima di modificarli. Quello che mi piacerebbe fare è essere in grado di riflettere un elenco di tabelle e colonne, quindi inviare comandi di aggiornamento direttamente al database. Sarebbe simile a questa:

var command = String.Format("UPDATE [{0}] SET [{1}] = {{1}} WHERE [{1}] = {{0}}; ", fk.FromTableName, fk.FromColumnName); 
dataContext.ExecuteStoreCommand(command, new Object[] { oldID, newID }); 

In LINQ to SQL questo era in realtà abbastanza facile ... 20 linee di riflessione sul codice generato automaticamente LINQ e mi è stato fatto, ma siamo passati a EF di recente e ho non è possibile trovare i nomi delle colonne chiave esterna tramite EF.

Un esempio semplificato di ciò che sto cercando: se ho un oggetto chiamato Employee con una proprietà di navigazione chiamata Manager e una chiave esterna di ManagerID, allora voglio sapere che Manager è la mia proprietà di navigazione e lo storage sottostante è la proprietà ManagerID. Voglio farlo rigorosamente attraverso la riflessione o i metadati in modo da poter creare una query dinamica da esso.

+1

hai un voto negativo quindi presumo di non essere l'unico ad avere un po 'di problemi a capire cosa stai cercando. puoi semplicemente fare 'employee.managerId' o' employee.manager.id'? devi sapere qual è la convenzione, il tuo DBA non può semplicemente cambiare il DB senza che questo influenzi il tuo progetto in altri modi. – Eonasdan

+0

@ Eonasdan - grazie. Mi stavo chiedendo perché fossi downvoted. Ho riscritto interamente per sperare di renderlo molto più chiaro. Sfortunatamente ora è molto più lungo, e stavo cercando di farla breve. – pbarranis

risposta

1

Una volta che hai usato le idee nella questione legata per arrivare al EntityType che ti interessa, si noti che EntityType eredita da EntityTypeBase, che ha una proprietà KeyMembers che è una raccolta di tutte le EdmMembers che partecipano al la chiave dell'entità.

Ogni EdmMember ha uno Name che sarà la stringa "ManagerID" che si cerca.

+1

Questa è una buona idea, ma ho bisogno di ottenere il nome della chiave esterna sull'oggetto corrente, non sulla chiave dell'oggetto estraneo. È la differenza tra myObject.ManagerID e myObject.Manager.ID. Non usiamo la convenzione di Manager.ManagerID - usiamo Manager.ID - quindi le colonne sono nominate in modo diverso su ciascuna estremità. – pbarranis

1

Solo per risparmiare tempo, voglio buttare fuori questo è non la risposta corretta, ma è possibile fare ciò che sto chiedendo attraverso le viste di sistema in SQL. Ho provato questo e funziona, ma mi dà fastidio che potrei ottenere questi dati così facilmente attraverso LINQ to SQL, ma non riesco a trovarlo affatto in EF. Se non ci sono alternative dovrò usare la soluzione qui sotto. (Ma EF deve avere questi dati internamente da qualche parte ... Voglio solo accesso ad esso.)

select K.name as RelationshipName, T1.name as FromTable, C1.name as FromColumn, T2.name as ToTable, C2.name as ToColumn 
from sys.foreign_keys as K 
join sys.foreign_key_columns as C on K.object_id = C.constraint_object_id 
join sys.columns as C1 on K.parent_object_id = C1.object_id 
join sys.tables as T1 on K.parent_object_id = T1.object_id 
join sys.columns as C2 on K.referenced_object_id = C2.object_id 
join sys.tables as T2 on K.referenced_object_id = T2.object_id 
where C1.column_id = C.parent_column_id 
and C2.column_id = C.referenced_column_id 
and T2.Name = 'Employee' 
order by T1.Name, C1.Name 

Speriamo che questo distacco risposta sbagliata è almeno utile a qualcuno diverso da me ... (anche, appena cronaca questa soluzione ha bisogno di molto più codice per funzionare con PK multi-colonna - i miei sono tutti a colonna singola).