Impossibile salvare i tipi ereditati di Entity Framework

.net entity-framework inheritance savechanges table-per-type

Domanda

Ho implementato alcune ereditarietà di tipo table-per-type nel mio modello di dati (fondamentalmente un tipo BaseEntity con tutte le informazioni di base per i miei articoli e un tipo di Employer che eredita dall'elemento BaseEntity ). Tutto sembra essere impostato correttamente e quando si utilizzano le Entità (tramite ADO.net Data Services o tramite Linq alle Entità) posso vedere il tipo di Employer e le cose sembrano andar bene. Il problema inizia quando creo una nuova entità Employer e provo a salvarla.

Nel contesto che non sembra essere un elemento .AddToEmployer (solo e AddObject o AddToBaseEntity ).

Se utilizzo AddObject("Employer", NewEmployer) ottengo e messaggio di errore di:

Non è stato possibile trovare il nome EntitySet "DataEntities.Employer".

Se utilizzo AddToBaseEntity(NewEmployer) viene visualizzato un messaggio di errore di:

Impossibile determinare un ordine valido per le operazioni dipendenti. Le dipendenze possono esistere a causa di vincoli di chiavi estranee, requisiti del modello o valori generati dal punto vendita.

Ho perso un passaggio nella creazione dell'eredità? Esiste un modo specifico per salvare oggetti ereditati? Che cosa sto facendo di sbagliato? Suppongo che il problema di base sia che dovrei avere un AddToEmployer , cosa devo fare per ottenere quello esposto? Sembra strano che non sia un'opzione dal momento che posso vedere il tipo di datore di lavoro sul lato client e posso fare cose come:

var NewEmployer = new Employer() - che sembra suggerire che io possa vedere il Datore di lavoro digita bene.

Risposta accettata

Ho cambiato un paio di cose e sono riuscito a farlo funzionare. Non sono particolarmente sicuro di quale fosse il problema di base, ma volevo pubblicare ciò che ho fatto per riferimento.

Tabelle ricostruite: ho ricostruito le tabelle iniziando solo con le colonne ID / chiave e una singola colonna di dati.

Rimossi campi auto incrementali aggiuntivi: avevo un ID autoincrementante su BaseEntity e sul Datore di lavoro. Ho rimosso l'ID autoincrementante sul Datore di lavoro e ho appena riportato la colonna Employer.BaseEntityID e la chiave esterna a BaseEntity.BaseEntityID. (questo sembra essere stato il colpevole, ma avevo l'impressione che fosse permesso)

Sfortunatamente ciò porta al problema che le classi ereditate nel framework entità non possono avere proprietà di navigazione (tutte le proprietà di navigazione devono essere nell'entità di base), quindi l'ereditarietà si dimostrerà non utilizzabile per le nostre esigenze.


Risposta popolare

Il mio nome è Phani e lavoro con il team ADO.NET Data Services.

I metodi ResolveName e ResolveType consentono di personalizzare le informazioni sul tipo che il client scrive nel payload inviato al server e in che modo viene materializzato il carico utile della risposta dal server.

Aiutano a risolvere i tipi sul client e sono utili in molti scenari, un paio di esempi sono:

  1. La gerarchia di tipi delle entità si trova sul client diversa rispetto al server.
  2. I tipi di entità esposti dal servizio partecipano all'ereditarietà e si desidera lavorare con i tipi derivati sul client.

ResolveName è usato per cambiare il nome dell'entità che mettiamo sul filo quando facciamo una richiesta al server.

Considera questo modello di dati: sul server

public class Employee {
    public int EmployeeID {get;set;}
    public string EmployeeName {get;set;}
}

public class Manager:Employee {
    public List<int> employeesWhoReportToMe {get;set;}
}

Quando si utilizza il client per lavorare con le istanze del tipo di entità Manager, dopo aver inviato le modifiche al server, ci si aspetta che le informazioni sul tipo siano presenti nel payload quando le entità partecipano all'ereditarietà.

context.AddObject("Employees",ManagerInstance ); <-- add manager instance to the employees set.
context.SaveChanges();

Tuttavia, quando il client serializza questo payload, inserisce "Employee" come nome del tipo che non è quello che è previsto sul server. Quindi devi fornire un name resolver sul client,

context.ResolveName = delegate(Type entityType){
    //do what you have to do to resolve the type to the right type of the entity on the server
    return entityType.FullName;
}

un resolver di tipo viene utilizzato allo stesso modo.

context.ResolveType = delegate(string entitySetName){
    //do what you have to do to convert the entitysetName to a type that the client understands
    return Type.GetType(entitySetName);
}


Related

Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow