如何解决内存存储列表中的 EF Core
我对整个 EF Core 内存数据库概念还很陌生,所以我可能在这里遗漏了一些重要的东西,但我迟早需要弄清楚这一点。
我想要实现的是将一个包含其他对象列表的对象添加到数据库中。 虽然原始数据类型存储正确,但列表似乎始终为空。
public class Race
{
public int RaceId { get; set; }
public int Year { get; set; }
public List<Vehicle> AllRunningVehicles { get; set; }
public List<Vehicle> AllRepairingVehicles { get; set; }
public List<Vehicle> AllDeadVehicles { get; set; }
public Race()
{
//AllRunningVehicles = new List<Vehicle>();
//AllRepairingVehicles = new List<Vehicle>();
//AllDeadVehicles = new List<Vehicle>();
}
}
这里是控制器
public class RaceController : Controller
{
private readonly RaceContext _raceContext;
public RaceController(RaceContext Rcontext)
{
_raceContext = Rcontext;
}
[HttpPost]
[Route("[controller]/[action]")]
public async Task<ActionResult<Race>> PostRaceItem(int year)
{
Race raceItem = new Race();
raceItem.Year = year;
raceItem.AllRunningVehicles = new List<Vehicle>();
raceItem.AllRepairingVehicles = new List<Vehicle>();
raceItem.AllDeadVehicles = new List<Vehicle>();
await _raceContext.RaceItems.AddAsync(raceItem);
await _raceContext.SaveChangesAsync();
return raceItem;
}
[HttpGet]
[Route("[controller]/[action]")]
public async Task<ActionResult<Race>> GetRaceItem(int raceID)
{
var raceItem = await _raceContext.RaceItems.FindAsync(raceID);
if (raceItem == null)
{
return NotFound();
}
return raceItem;
}
}
我尝试在 Ctor 中创建列表,但这样它们总是空的,存储在其中的数据总是被清除,我不想这样做。我将包括 Context 和 Startup 类,以防万一他们需要一些我不知道的额外配置。
public class RaceContext : DbContext
{
public RaceContext(DbContextOptions<RaceContext> options) : base(options) { }
public DbSet<Race> RaceItems { get; set; }
}
和启动
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<RaceContext>(opt => opt.UseInMemoryDatabase("RaceList"));
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1",new OpenApiInfo { Title = "TEST",Version = "v1" });
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app,IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json","TEST v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
解决方法
考虑在使用 EF 时您希望如何将数据存储在数据库中会有所帮助。在您的情况下,考虑到同一类的 3 个集合,您提出的结构几乎是不可能的。原始类型映射到表中的字段,对象引用和集合映射到相关表。
您有两个相关的实体:Race 和 Vehicle。假设有几辆车参加一场比赛,任何一辆车可以参加几场比赛,这就形成了多对多的关系。车辆可以“行驶”、“修理”或“死亡”,实际上是车辆在给定比赛中的一种状态。
从数据库的角度来看,这意味着一个 Race 表、一个 Vehicle 表,然后是一个名为 RaceVehicles 之类的连接表。车辆的状态可以是 RaceVehicle 表/实体的一部分:
public class Race
{
[Key]
public int RaceId { get; set; }
public int Year { get; set; }
// ... Race details.
public virtual ICollection<RaceVehicle> RaceVehicles { get; set; } = new List<RaceVehicle>();
}
public class Vehicle
{
[Key]
public int VehicleId { get; set; }
public string Name { get; set; }
// ... Vehicle details...
}
public class RaceVehicle
{
[Key,Column(Order=0),ForeignKey("Race")]
public int RaceId { get; set; }
[Key,Column(Order=1),ForeignKey("Vehicle")]
public int VehicleId { get; set; }
public RaceStates State { get; set; } = RaceStates.Running;
public virtual Race Race { get; set; }
public virtual Vehicle Vehicle { get; set; }
}
public enum RaceStates
{
None = 0,Running,Repairing,Dead
}
这是第一步,但是对于一场比赛,它只会为所有州的比赛提供所有车辆。 (运行等)就实体而言,它们应该反映应用程序的数据状态。当我们去展示比赛的细节时,我们将要根据他们的比赛状态来分解车辆。我们可以将实体传递给视图,但最好为视图提供一个格式化为仅包含视图所需数据的模型。这有助于防止出现意外,并允许我们将数据格式化为适合视图的格式:
[Serializable]
public class RaceViewModel
{
public int RaceId { get; set; }
public int RaceYear { get; set; }
public ICollection<VehicleViewModel> RunningVehicles { get; set; } = new List<VehicleViewModel>();
public ICollection<VehicleViewModel> RepairingVehicles { get; set; } = new List<VehicleViewModel>();
public ICollection<VehicleViewModel> DeadVehicles { get; set; } = new List<VehicleViewModel>();
}
[Serializable]
public class VehicleViewModel
{
public int VehicleId { get; set; }
public string VehicleName { get; set; }
// Vehicle details for the view.
}
当我们获取数据时,我们将实体(数据状态)投影到视图模型(视图状态)中
using (var context = new AppDbContext())
{
var viewModels = context.Races
.Where(r => r.Year >= 2020 /*insert conditions*/)
.Select(r => new RaceViewModel
{
RaceId = r.RaceId,RaceYear = r.Year,RunningVehicles = r.RaceVehicles
.Where(rv => rv.State == RaceStates.Running)
.Select(rv => new VehicleViewModel
{
VehicleId = rv.Vehicle.VehicleId,VehicleName = rv.Vehicle.Name,}).ToList(),RepairingVehicles = r.RaceVehicles
.Where(rv => rv.State == RaceStates.Repairing)
.Select(rv => new VehicleViewModel
{
VehicleId = rv.Vehicle.VehicleId,DeadVehicles = r.RaceVehicles
.Where(rv => rv.State == RaceStates.Dead)
.Select(rv => new VehicleViewModel
{
VehicleId = rv.Vehicle.VehicleId,}).ToList()
}).ToList();
}
这为您提供了一个适用于根据状态拆分车辆列表的视图的模型。您可以在实体本身中设置类似的属性,按每个状态返回 Vehicles,但是您需要配置这些属性,以便 EF 忽略它们,并且只有在加载 RaceVehicles 集合时它们才会起作用。 (要么预先加载,要么触发延迟加载(如果可用)
使用 Select
而不是返回实体的投影的好处是 Select
或 Automapper 的 ProjectTo
将自动调整生成的 SQL 以从相关表/实体中拉回所需的任何字段。如果您自己返回实体,您需要记住急切加载所有相关实体,否则您将因延迟加载调用而导致严重的性能损失,或者如果延迟加载被禁用,则会留下#null 引用.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。