首页 > 解决方案 > MVC 保存到两个表

问题描述

项目有两张桌子。它需要从传感器到数据库的值。如何保存到两个有关系的数据库?代码可能是错误的。也许有人可以帮忙。

public class Assets
    {
        public int id { get; set; }
        public int? sensorid { get; set; }
        public int? value { get; set; }
        public DateTime? DateTime { get; set; }
        public virtual Sensors Sensors { get; set; }
    }

 public class Sensors
{
    public int id { get; set; }
    public int? sensorname { get; set; }
    public virtual ICollection<Assets> Assets { get; set; }
}

控制器

 public ActionResult Index(Sensors sensors, Assets assets)
    {

        int[] response = client.ReadHoldingRegisters(StartAddress, quantity);
        client.Disconnect();
        Assets asst = new Assets();
        Sensors sns = new Sensors();

        for (int i = 0; i < quantity; i++)
        {
            asst.value = response[i];
            sns.id = StartAddress;
            db.Assets.Add(asst);
            for (int x = 0; x < 3; x++)
            {
                db.Sensors.Add(sns);

            }
            db.SaveChanges();
        }    

标签: c#sql-serverentity-frameworklinq

解决方案


首先,如果您仍然能够更改标识符的名称,我的建议是坚持实体框架编码约定。这样做可以让您和其他人更容易理解您的代码。

我建议的更改之一是对单个项目使用单数名词,对集合使用复数名词。在这种情况下,我们将有一个资产类,而您的 DbContext 将有一个资产的 DbSet。

除此之外,你的一段代码使用了很多变量,我们必须猜测它们是什么以及它们的功能是什么:StartAddress、数量、客户端、db。使用大写坚持一个约定:StartAddress 是一个变量吗?或者它是一个类名?

回到你的问题

从您的代码中,我看到传感器和资产之间存在不那么标准的一对多关系。每个Sensor有零个或多个Asset,每个Asset最多可以属于一个Sensor,即属性SensorId所指的那个。如果 SensorId 为 null,则资产不属于任何 Sensor。

如果不是这种情况,但每个资产只属于一个传感器,则考虑将属性 SensorId 的类型更改为int而不是int?. 这样就不可能添加不属于任何资产的传感器。

从您的代码中,我收集到 aClient有一个 function ReadHoldingRegisters。此方法返回一个整数数组。数组的长度可能等于数量的值。唉,你没有提到这是否总是如此。

StartAddres 表示现有 Sensor 的 ID。我知道传感器存在于数据库中,否则它不会有 ID。所以我不确定你为什么要四次添加同一个传感器。如果它已经在数据库中,您不必再添加它,如果不是,您应该添加它而不给它一个 ID。在这种情况下,SaveChanges 将确保 Sensor 获得一个 Id。

传感器已经存在

您不必再将传感器添加到数据库中,您只需添加一些资产,每个响应一个资产。

Asset.Value 等于对应的 Response 值,每个 Asset 都属于 Sensor,主键等于 StartAddress。外键 SensorId 指的是这个 Sensor,所以 SensorId 需要设置为 StartAddress。

int[] assetValues = client.ReadHoldingRegisters(startAddress, quantity);

// for every assetValue create an Asset with Value equal to assetValue
// and a foreign key equal to startAddress:
var assetsToAdd = assetValues
    .Select(assetValue => new Asset()
    {
        Value = assetValue,
        SensorId = startAddress,
    });

using (var dbContext = new MyDbContext(...))
{
    // Add the Assets in one call to DbSet.AddRange(IEnumerable)
    dbContext.Assets.AddRange(assetsToAdd);

    // and save the changes:
    dbContext.SaveChanges();
}

如果您对序列使用正确的标识符和正确的复数形式,对单个项目使用单数形式,您是否看到您的代码变得多么容易?

传感器还不存在

在这种情况下,您必须添加一个传感器。不能分配主键,所以不能填写 Asset.SensorId。幸运的是,实体框架足够聪明,可以为您解决这个问题:

int[] assetValues = client.ReadHoldingRegisters(startAddress, quantity);

using (var dbContext = new MyDbContext(...))
{
    // Add one Sensor with all its Assets in one go
    dbContext.Sensors.Add(new Sensor()
    {
        // fill the Sensor properties that you know.
        // don't fill the Id
        ...

        Assets = assetValues
                 .Select(assetValue => new Asset()
                 {
                      Value = assetValue,
                      // no need to fill SensorId, Entity framework will do that for you
                      ... // if needed: fill other Asset properties
                 })
                 .ToList(),
    });
    dbContext.SaveChanges(); 
}

如果需要,您可以分两步执行此操作:

using (var dbContext = new MyDbContext(...))
{
    // Add one Sensor without Assets
    var addedSensor = dbContext.Sensors.Add(new Sensor()
    {
        // fill the Sensor properties that you know.
        // don't fill the Id, nor property Assets
        ...
    });

    // Add the Assets in one call to DbSet.AddRange(IEnumerable)
    dbContext.Assets.AddRange(assetValues.Select(assetValue => new Asset()
                     {
                         Value = assetValue,
                         Sensor = addedSensor,
                     }));
    dbContext.SaveChanges(); 
}

推荐阅读