Non sono sicuro di come ottenere le informazioni necessarie utilizzando EF Core con un'app .NET Core. Ho due tabelle di database: OBJECTS e TAG con una relazione molti-a-molti (utilizzando una terza tabella di join OBJECTTAGS). Voglio ottenere tutti gli oggetti (circa 1400) insieme ai loro tag associati.
Questi sono i miei tre modelli:
using System;
using System.Collections.Generic;
namespace ContentMarketplace.Models
{
public partial class Object
{
public int ObjectId { get; set; }
...
public virtual List<ObjectTag> ObjectTags { get; set; }
}
}
namespace ContentMarketplace.Models
{
public partial class Tag
{
public int TagId { get; set; }
...
public virtual List<ObjectTag> ObjectTags { get; set; }
}
}
namespace ContentMarketplace.Models
{
public partial class ObjectTag
{
public int ObjectId { get; set; }
public virtual Object Object { get; set; }
public int TagId { get; set; }
public virtual Tag Tag { get; set; }
}
}
E questo è ciò che c'è nel metodo OnModelCreating () nel mio contesto:
modelBuilder.Entity<ObjectTag>(entity =>
{
entity.HasKey(e => new { e.ObjectId, e.TagId });
entity.HasOne(ot => ot.Object)
.WithMany(o => o.ObjectTags)
.HasForeignKey(ot => ot.ObjectId);
entity.HasOne(ot => ot.Tag)
.WithMany(t => t.ObjectTags)
.HasForeignKey(ot => ot.TagId);
});
Questo problema sorge quando provo a restituire i dati nel mio ObjectController.cs
namespace ContentMarketplace.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ObjectController : ControllerBase
{
private readonly ContentMarketplaceContext _context;
public ObjectController(ContentMarketplaceContext context)
{
_context = context;
}
[HttpGet]
public ActionResult<List<ContentMarketplace.Models.Object>> GetAll()
{
return _context.Objects
.Include(o => o.ObjectTags)
.ThenInclude(ot => ot.Tag)
.ToList();
}
}
}
Includi (). ThenInclude () crea una relazione circolare in cui una richiesta HTTP non restituisce solo le informazioni del tag associate a ciascun oggetto, ma tutti gli oggetti associati a ciascuno di tali tag e così via, bloccando il browser.
Se tolgo il ThenInclude () funziona bene, ma non restituisce tutte le informazioni del tag non nel mio modello ObjectTag.
So che questo ha a che fare con il caricamento automatico di EF Core che è già nel contesto (come le note "tip" qui https://docs.microsoft.com/en-us/ef/core/querying/related-data ) ma Non so in quale altro modo restituire SOLO l'oggetto e i tag senza andare oltre.
Se si utilizza Include
o Theninclude
nella query, verranno creati riferimenti circolari. JSON non può gestire riferimenti circolari. Puoi facilmente superare questo problema usando Select
query.
Senza DTO:
Scrivi il tuo GetAll()
controller GetAll()
come segue:
[HttpGet]
public IActionResult GetAll()
{
var objectList = _context.Objects.Select(o => new
{
o.ObjectId,
Tags = o.ObjectTags.Select(ot => ot.Tag).ToList()
}).ToList();
return Ok(objectList);
}
Con DTO:
Scrivi la tua classe DTO come segue:
public class ObjectDto
{
public int ObjectId { get; set; }
....
public List<Tag> Tags { get; set; }
}
Quindi il tuo GetAll()
controllo GetAll()
dovrebbe essere il seguente:
[HttpGet]
public ActionResult<List<ObjectDto>> GetAll()
{
var objectList = _context.Objects.Select(o => new ObjectDto
{
ObjectId = o.ObjectId,
Tags = o.ObjectTags.Select(ot => ot.Tag).ToList()
}).ToList();
return objectList;
}
Nota: se si utilizza Select
all'interno della query, non è necessario utilizzare Include
o Theninclude
.
Spero che ora funzioni come previsto!
Il tuo problema è causato dal riferimento del loop, puoi provare a seguire in basso per ignorare il riferimento del loop.
services.AddMvc()
.AddJsonOptions(opt => {
opt.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
Per un'altra opzione, puoi provare a restituire ObjectModel
con List<Tag>
direttamente invece di List<ObjectTag>
ObjectModel
public partial class ObjectModel
{
public int ObjectId { get; set; }
public string Name { get; set; }
public virtual List<Tag> Tags { get; set; }
}
domanda
public List<Models.ObjectModel> GetAll()
{
//return _db.Object
// .Include(o => o.ObjectTags)
// .ThenInclude(ot => ot.Tag)
// .ToList();
return _db.Object
.Include(o => o.ObjectTags)
.ThenInclude(ot => ot.Tag)
.Select(r => new Models.ObjectModel
{
ObjectId = r.ObjectId,
Name = r.Name,
Tags = r.ObjectTags.Select(ot => ot.Tag).ToList()
})
.ToList();
}