微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

内存存储列表中的 EF Core

如何解决内存存储列表中的 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 举报,一经查实,本站将立刻删除。