Получение данные из таблицы. Web API. ASP.NET CORE из базы данных MS SQL Server
Я начал создавать свой собственный веб сервис. Используемые технологии (ASP.NET CORE Web API, Entity framework core) а также для соединение базу данный использовал MS SQL Server.
Первое, что делал это создал модель, репозиторий а также контекст базу данных и там соединил таблицы между собой и мигрировал их, а потом перенёс все библиотеку классов и там ещё раз мигрировал
Второе, Создал контроллеры для использование операцию CRUD. И теперь возникает проблема, когда вызываю контроллер определенного таблицы, данные с другого таблицы не получаю, может быть я где-то накосячил. Можете найти где именно проблемы. Заранее спасибо.
WebServiceContext.cs
using ClassLibrary.Contexts_Repositories_Models.Models;
using Microsoft.EntityFrameworkCore;
namespace ClassLibrary.Contexts_Repositories_Models.Context;
public class WebServiceContext: DbContext
{
public WebServiceContext() { }
public WebServiceContext(DbContextOptions<WebServiceContext> options): base(options)
{
Database.EnsureDeleted();
Database.EnsureCreated();
}
public DbSet<Airport> Airports { get; set; }
public DbSet<CodeAirport> CodeAirports { get; set; }
public DbSet<DepartureAndArrival> DeparturesAndArrivals { get; set; }
public DbSet<Information> Informations { get; set; }
public DbSet<PitStop> PitStops { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=HP-NETBOOK-WIN\\SQLEXPRESS;Database=itvdnDB;User id=itvdn;Password=1;Trusted_Connection=True;TrustServerCertificate=True");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
/// Airports Table
modelBuilder.Entity<Airport>(entity =>
{
entity.Property(x => x.Id).IsRequired();
entity.HasKey(x => x.Id);
entity.Property(x => x.Country).IsRequired();
entity.Property(x => x.City).IsRequired();
entity.Property(x => x.NameAirport).IsRequired();
entity.Property(x => x.Airline).IsRequired();
entity.Property(x => x.Active).IsRequired();
///Airport-Information, One-To-One
entity.HasOne(a => a.Information)
.WithOne(i => i.Airport)
.HasForeignKey<Information>(a => a.AirportId);
///Airport-CodeAirport, One-To-Many
entity.HasMany(a => a.CodeAirports)
.WithOne(c => c.Airport)
.HasForeignKey(c => c.AirportId);
///Airport-DepartureAndArrival, One-To-Many
entity.HasMany(a => a.DepartureAndArrivals)
.WithOne(da => da.Airport)
.HasForeignKey(da => da.AirportId);
///Airport-PitStop, One-To-Many
entity.HasMany(a => a.PitStops)
.WithOne(p => p.Airport)
.HasForeignKey(p => p.AirportId);
entity.ToTable("Airports");
});
//CodeAirports Table
modelBuilder.Entity<CodeAirport>(entity =>
{
entity.Property(x => x.Id).IsRequired();
entity.HasKey(x => x.Id);
entity.Property(x => x.Type).IsRequired();
entity.Property(x => x.Code).IsRequired();
entity.ToTable("CodeAirports");
});
///Informations Table
modelBuilder.Entity<Information>(entity =>
{
entity.Property(x => x.Id).IsRequired();
entity.HasKey(x => x.Id);
entity.Property(x => x.NumberBoard).IsRequired();
entity.Property(x => x.NumberFlight).IsRequired();
entity.ToTable("Informations");
});
///DepartureAndArrivals Table
modelBuilder.Entity<DepartureAndArrival>(entity =>
{
entity.Property(x => x.Id).IsRequired();
entity.HasKey(x => x.Id);
entity.Property(x => x.Departure).IsRequired();
entity.Property(x => x.Arrival).IsRequired();
entity.Property(x => x.Routing).IsRequired();
entity.Property(x => x.Distance).IsRequired();
entity.HasMany(da => da.PitStops)
.WithOne(ps => ps.DepartureAndArrival)
.HasForeignKey(ps => ps.DepartureAndArrivalId);
entity.ToTable("DeparturesAndArrivals");
});
//PitStops Table
modelBuilder.Entity<PitStop>(entity =>
{
entity.Property(x => x.Id).IsRequired();
entity.HasKey(x => x.Id);
entity.Property(x => x.PitStopCity).IsRequired();
entity.ToTable("PitStops");
});
}
}
Airport.cs
namespace ClassLibrary.Contexts_Repositories_Models.Models;
public class Airport
{
public int Id { get; set; }
public string? Country { get; set; }
public string? City { get; set; }
public string? NameAirport { get; set; }
public string? Airline { get; set; }
public bool Active { get; set; }
public Information? Information { get; set; }
public List<CodeAirport> CodeAirports { get; set; }
public List<PitStop> PitStops { get; set; }
public List<DepartureAndArrival> DepartureAndArrivals { get; set; }
public Airport()
{
CodeAirports = new List<CodeAirport>();
PitStops = new List<PitStop>();
DepartureAndArrivals = new List<DepartureAndArrival>();
}
}
AirportRepository.cs
using ClassLibrary.Contexts_Repositories_Models.Context;
using ClassLibrary.Contexts_Repositories_Models.Models;
using Microsoft.EntityFrameworkCore;
namespace ClassLibrary.Contexts_Repositories_Models.Repositories;
public class AirportRepository : IRepository<Airport>
{
#region FIELDS
private WebServiceContext dbContext;
private bool disposed = false;
#endregion
#region CONSTRUCTOR
public AirportRepository(WebServiceContext dbContext) => this.dbContext = dbContext;
#endregion
#region METHODS
/// <summary>
/// Метод получение коллекция объекта типа Airport
/// </summary>
/// <returns>Возвращает коллекция объекта типа Airport</returns>
public IEnumerable<Airport> GetAll()
{
foreach(var airport in dbContext.Airports)
{
if (airport.CodeAirports.Count==0)
throw new Exception("CodeAirports type collection is null!!!!");
else if (airport.PitStops.Count == 0)
throw new Exception("PitStops type collection is null!!!!");
else if(airport.DepartureAndArrivals.Count == 0)
throw new Exception("DepartureAndArrivals type collection is null!!!!");
if (airport.Information == null)
throw new Exception("Information type is null!!!!");
}
return dbContext.Airports;
}
/// <summary>
/// Метод получение объекта типа Airport по id
/// </summary>
/// <param name="id">id объекта типа Airport</param>
/// <returns>Возвращает объект типа Airport</returns>
public Airport GetById(int id)
{
Airport? airport = dbContext.Airports.FirstOrDefault(x => x.Id == id);
if (airport == null)
return null!;
return airport;
}
/// <summary>
/// Создание объекта типа Airport, а также добавление в таблицу Airports из базы данных
/// </summary>
/// <param name="airport">Объект типа Airport</param>
public void Create(Airport airport)
{
dbContext.Airports.Add(airport);
dbContext.SaveChanges();
}
/// <summary>
/// Метод, изменение объекта типа Airport, а также сохранение в таблицу Airports из базы данных
/// </summary>
/// <param name="airport">Объект типа Airport</param>
public void Update(Airport airport)
{
dbContext.Entry(airport).State = EntityState.Modified;
dbContext.SaveChanges();
}
/// <summary>
/// Метод удаление объекта типа Airport, а также изменение в таблицы Airports из базы данных
/// </summary>
/// <param name="id">id объекта типа Airport</param>
public void Delete(int id)
{
Airport? airport = GetById(id);
if (airport != null)
{
dbContext.Airports.Remove(airport);
dbContext.SaveChanges();
}
}
/// <summary>
/// Виртуальный метод, для удаление контекст базы данных
/// </summary>
/// <param name="disposing">Для вызова в контексте базы данных метод,Dispose в интерфейсе IDisposable</param>
public virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
dbContext.Dispose();
}
}
disposed = true;
}
/// <summary>
/// Метод для вызова виртуального метода Dispose, а также вызов сборщика мусора (Garbage Collector)
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
AirportAPIController.cs
using ClassLibrary.Contexts_Repositories_Models.Context;
using ClassLibrary.Contexts_Repositories_Models.Models;
using ClassLibrary.Contexts_Repositories_Models.Repositories;
using Microsoft.AspNetCore.Mvc;
namespace ITVDN_WEBAPI_PRACTICE.Controllers;
[Route("api/[controller]")]
[ApiController]
public class AirportAPIController : ControllerBase
{
#region FIELDS
private IRepository<Airport> _repository;
private readonly ILogger<AirportAPIController> logger;
#endregion
#region CONSTRUCTOR
public AirportAPIController(ILogger<AirportAPIController> logger)
{
_repository = new AirportRepository(new WebServiceContext());
this.logger = logger;
}
#endregion
#region METHODS
/// <summary>
/// Метод, получение коллекцию класса Airport в асинхронном запросе (GET)
/// </summary>
/// <returns>Возвращает асинхронный обобщенный тип класса Task. Внутри обобщенного класса Task,
/// имеется другой обобщенный класс ActionResult. А внутри обобщенного класса ActionResult, возвращает
/// обобщенную коллекцию типа IEnumerable, внутри которого тип класса Airport</returns>
[HttpGet]
public async Task<ActionResult<IEnumerable<Airport>>> GetAllAirports()
=> await Task.Run(() => Ok(_repository.GetAll()));
/// <summary>
/// Метод, получение объекта класса Airport, через id в асинхронном запросе (GET)
/// </summary>
/// <param name="id">id объекта класса Airport</param>
/// <returns>Возвращает асинхронный обобщенный тип класса Task. Внутри обобщенного класса Task,
/// имеется другой обобщенный класс ActionResult. А внутри обобщенного класса ActionResult, возвращает
/// объект класса Airport
/// </returns>
[HttpGet("{id:int}")]
public async Task<ActionResult<Airport>> GetAirportByIdAsync(int id)
{
if (id < 0)
{
logger.LogError("id cannot be negative");
return await Task.Run(() => BadRequest("id cannot be negative"));
}
var airport = _repository.GetById(id);
if (airport.Information == null)
{
logger.LogError("Information is null!!!");
return await Task.Run(() => NotFound("Information is null!!!"));
}
else if (airport.CodeAirports == null)
{
logger.LogError("CodeAirports is null!!!");
return await Task.Run(() => NotFound("CodeAirports is null!!!"));
}
else if (airport.DepartureAndArrivals == null)
{
logger.LogError("DepartureAndArrivals is null!!!");
return await Task.Run(() => NotFound("DepartureAndArrivals is null!!!"));
}
else if (airport.PitStops == null)
{
logger.LogError("PitStops is null!!!");
return await Task.Run(() => NotFound("PitStops is null!!!"));
}
else
{
logger.LogError("airport is null!!!");
return await Task.Run(() => NotFound("airport is null!!!"));
}
return await Task.Run(() => Ok(airport));
}
/// <summary>
/// Метод, добавление объекта класса Airport, в таблицу Airports, в асинхронном запросе (POST)
/// </summary>
/// <param name="airport">Объект класса Airport</param>
/// <returns>Возвращает созданный объект асинхронный обобщенный тип класса Task. Внутри обобщенного класса Task,
/// имеется другой обобщенный класс ActionResult. А внутри обобщенного класса ActionResult, возвращает
/// объект класса Airport
/// </returns>
[HttpPost]
public async Task<ActionResult<Airport>> CreateAirportAsync([FromQuery] Airport airport)
{
if (airport.Information == null)
{
logger.LogError("Information is null!!!");
return await Task.Run(() => NotFound("Information is null!!!"));
}
else if (airport.CodeAirports == null)
{
logger.LogError("CodeAirports is null!!!");
return await Task.Run(() => NotFound("CodeAirports is null!!!"));
}
else if (airport.DepartureAndArrivals == null)
{
logger.LogError("DepartureAndArrivals is null!!!");
return await Task.Run(() => NotFound("DepartureAndArrivals is null!!!"));
}
else if (airport.PitStops == null)
{
logger.LogError("PitStops is null!!!");
return await Task.Run(() => NotFound("PitStops is null!!!"));
}
else
{
logger.LogError("airport is null!!!");
return await Task.Run(() => NotFound("airport is null!!!"));
}
_repository!.Create(airport);
return await Task.Run(() => Ok(airport));
}
/// <summary>
/// Метод, изменение объекта класса Airport из таблицы Airports, в асинхронном запросе (PUT)
/// </summary>
/// <param name="airport">Объект класса Airport</param>
/// <returns>Возвращает асинхронный обобщенный тип класса Task. Внутри обобщенного класса Task,
/// имеется другой обобщенный класс ActionResult. А внутри обобщенного класса ActionResult, возвращает
/// объект класса Airport
/// </returns>
[HttpPut]
public async Task<ActionResult<Airport>> UpdateAirportAsync([FromQuery] Airport airport)
{
if (airport.Information == null)
{
logger.LogError("Information is null!!!");
return await Task.Run(() => NotFound("Information is null!!!"));
}
else if (airport.CodeAirports == null)
{
logger.LogError("CodeAirports is null!!!");
return await Task.Run(() => NotFound("CodeAirports is null!!!"));
}
else if (airport.DepartureAndArrivals == null)
{
logger.LogError("DepartureAndArrivals is null!!!");
return await Task.Run(() => NotFound("DepartureAndArrivals is null!!!"));
}
else if (airport.PitStops == null)
{
logger.LogError("PitStops is null!!!");
return await Task.Run(() => NotFound("PitStops is null!!!"));
}
else
{
logger.LogError("airport is null!!!");
return await Task.Run(() => NotFound("airport is null!!!"));
}
_repository.Update(airport);
return await Task.Run(() => Ok(airport));
}
/// <summary>
/// Метод, удаление объекта класса Airport через id из таблицы Airports, в аснхронном запросе (DELETE)
/// </summary>
/// <param name="id">id объекта класса Airport</param>
/// <returns>Возвращает асинхронный обобщенный тип класса Task. Внутри обобщенного класса Task,
/// имеется другой обобщенный класс ActionResult. А внутри обобщенного класса ActionResult, возвращает
/// объект класса Airport
/// </returns>
[HttpDelete("{id:int}")]
public async Task<ActionResult<Airport>> DeleteAirportAsync(int id)
{
if (id < 0)
{
logger.LogError("id cannot be negative");
return await Task.Run(() => BadRequest("id cannot be negative"));
}
Airport airport = _repository.GetById(id);
if (airport.Information == null)
{
logger.LogError("Information is null!!!");
return await Task.Run(() => NotFound("Information is null!!!"));
}
else if (airport.CodeAirports == null)
{
logger.LogError("CodeAirports is null!!!");
return await Task.Run(() => NotFound("CodeAirports is null!!!"));
}
else if (airport.DepartureAndArrivals == null)
{
logger.LogError("DepartureAndArrivals is null!!!");
return await Task.Run(() => NotFound("DepartureAndArrivals is null!!!"));
}
else if (airport.PitStops == null)
{
logger.LogError("PitStops is null!!!");
return await Task.Run(() => NotFound("PitStops is null!!!"));
}
else
{
logger.LogError("airport is null!!!");
return await Task.Run(() => NotFound("airport is null!!!"));
}
_repository.Delete(id);
return await Task.Run(() => Ok(airport));
}
#endregion
}
Ответы (1 шт):
При любой попытке получения данных, для "присоединения" других таблиц вам нужно использовать метод .Include с указанием таблицы, которую хотите включить при запросе. Подробнее просто метод Include тут
В вашем случае, вам нужно изменить выши запросы, внутри репозитория, примерно вот так:
public Airport GetById(int id)
{
Airport? airport = dbContext.Airports
.Include(x => x.Information)
.Include(x => x.CodeAirports)
.Include(x => x.PitStops)
.Include(x => x.DepartureAndArrivals)
.FirstOrDefault(x => x.Id == id);
if (airport == null)
{
return null!;
}
return airport;
}
С именами могут быть ошибки, перепысывал вручную. Для остальных методов с получением данных сделайте аналогично, включив нужные вам таблицы
