Per la mia API sto usando Entity Framework Core con le prime migrazioni del codice. Ho creato alcune relazioni che stanno funzionando bene. Ora, ho aggiunto un'altra relazione (una a molte) e all'improvviso sono schiaffeggiato alle orecchie con questo errore:
Cannot insert explicit value for identity column in table 'Companies' when IDENTITY_INSERT is set to OFF."
Fuori dal campo, devo fare qualcosa di sbagliato ma non riesco proprio a capire cosa . Mi sono imbattuto in altre domande come questa in cui la risposta era "imposta IDENTITY_INSERT su ON" ma ciò non funziona per me poiché EF gestisce tutto.
La mia classe aziendale che può appartenere a un gruppo:
public class Company
{
// Primary key
public int Id { get; set; }
// The optional Id of a Group
public int? GroupID { get; set; }
...
}
E la classe di gruppo:
public class Group
{
// Primary key
public int Id { get; set; }
// Name of the Group
public string Name { get; set; }
// List of Companies in this group
public IEnumerable<Company> Companies { get; set; }
}
Il codice utilizzato per gestire il POST:
// POST api/groups
[HttpPost]
public async Task<IActionResult> Post([FromBody] Group group)
{
try
{
if (ModelState.IsValid)
{
_context.Groups.Add(group);
await _context.SaveChangesAsync();
return CreatedAtRoute("GetGroup", new { id = group.Id }, group);
}
return BadRequest(ModelState);
}
catch (Exception e)
{
return BadRequest($"Unable to create: {e.Message}");
}
}
Nel mio database, tutte le colonne, gli indici e le chiavi sono creati come previsto e proprio come tutti gli altri a molti rapporti che ho nella mia API. Ma questo caso specifico sembra solo finire nella miseria ...
La classe che sto cercando di aggiungere al database:
Il problema è che non vi è alcun suggerimento per EF di sapere se l' Company
(in base alla relazione di Group
) viene inserita esplicitamente o se si suppone che utilizzi quella preesistente dal database.
Poiché quelli istanziati sono disconnessi da DbContext
non vi è alcuna indicazione sul fatto che esistano o meno sul database dal momento in cui EF tenta di generare il suo comando SQL.
Non c'è un modo semplice qui, almeno non ce n'è stato per il momento in cui ho giocato con EF Core.
Dovresti o:
ID
invece della proprietà di navigazione, così potrai evitare questo quando possibile, oppure; Company
e collegalo al Group
) prima di salvare i dati desiderati (es .: prima di salvare il Group
). Quindi, ad esempio:
var companyDB = await context.Companies.SingleOrDefaultAsync(c => c.Id == group.Company.Id);
group.Company = companyDB;
context.Groups.Add(group);
await context.SaveChangesAsync();
Sì, stai facendo due viaggi nel database. Ecco perché suggerirei di utilizzare il primo approccio, quindi puoi evitare questo recupero e salvare l'entità del Group
direttamente nel DB.
Ciò, tuttavia, non vieta di inviare una visualizzazione di navigazione della Company
alla vostra vista. È sufficiente creare alcune classi relative all'entità che si correlano al database in modo da poter caricare / salvare i dati utilizzando questo tipo di entità e creare un oggetto Dto
che sarà l'input / output del punto finale ogni volta che sarà necessario.
È possibile collegarne uno in un altro utilizzando AutoMapper, Linq manuale o altri approcci.
Ho avuto un problema simile nel tentativo di salvare un'entità (ad esempio, Cat
) che aveva relazioni multiple con entità esistenti (proprietario della Owner
, indicando Person
). Oltre a a) ottenere la relazione (Persona) dal database prima di salvare l'entità ( Cat
) eb) aggiungere un'altra proprietà ( int PersonId
) all'entità ( Cat
), ho scoperto quale penso sia la soluzione migliore: c ) attenersi solo alle proprietà "navigazione" (non creare ulteriori int <<Name>>Id
proprietà int <<Name>>Id
) e, quando è necessario il riferimento, utilizzare cat.Owner = dbContext.Person.Attach(new Person { Id = 123 }).Entity;