【问题标题】:Insert to Database with ADO.NET Entity Data Model through OPC UA Client in C#通过 C# 中的 OPC UA 客户端使用 ADO.NET 实体数据模型插入​​数据库
【发布时间】:2017-12-11 19:13:35
【问题描述】:

我正在尝试使用来自OPCFoundation/UA-.NETStandard 的示例客户端使用 ADO.NET 实体数据模型写入数据库。我是 C# 的新手,我的问题是 lamda 表达式:

list.ForEach(i => i.Notification += OnNotification);

当服务器上的值发生更改时,客户端将收到实际值(这称为订阅)。下面的函数显示了函数OnNotification

private static void OnNotification(MonitoredItem item, MonitoredItemNotificationEventArgs e)
{
    foreach (var value in item.DequeueValues())
    {
        Console.WriteLine("{0}: {1}, {2}, {3}", item.DisplayName, value.Value, value.SourceTimestamp, value.StatusCode);
    }
}

函数的输出如下所示:

Column01: 4545, 11.12.2017 13:34, Good
Column02: 6767, 11.12.2017 13:34, Good
Column01: 4456, 11.12.2017 13:35, Good 
Column02: 5554, 11.12.2017 13:35, Good 
Column02: 6664, 11.12.2017 13:36, Good
Column01: 6233, 11.12.2017 13:37, Good 
Column02: 5123, 11.12.2017 13:37, Good 

当值更改时会生成输出,并一直持续到您按下某个键为止。请注意,有时一列不会出现,因为值保持不变。在这种情况下,可以将值作为 NULL 添加到数据库中。

为了将数据导入数据库,我想将OnNotification 函数修改为如下内容:

private static void OnNotification(MonitoredItem item, MonitoredItemNotificationEventArgs e)
    {
        Entities context = new Entities();
        dbName objData = new dbName();

        objData.SourceTimestamp = System.DateTime.Now;

        foreach (var value in item.DequeueValues())
        {
            switch (item.DisplayName)
            {
                case "Column01":
                    objData.Column01 = Convert.ToInt16(value.Value);
                    break;

                case "Column02":
                    objData.Columns02 = Convert.ToInt16(value.Value);
                    break;

                default:
                    Console.WriteLine("Unknown Displayname: {0}", item.DisplayName);
                    break;
            }

        }
        context.dbName.Add(objData);
        context.SaveChanges();

    }

现在我可以将值插入到 Column01 和 Column02,但只能插入不同的行。所以我在数据库中的表看起来像这样:

SourceTimestamp  | Column01 | Column02
11.12.2017 13:34 | 4545     | NULL
11.12.2017 13:34 | NULL     | 6767
11.12.2017 13:35 | 4456     | NULL
11.12.2017 13:35 | NULL     | 5554
11.12.2017 13:36 | NULL     | 6664
11.12.2017 13:37 | 6233     | NULL
11.12.2017 13:37 | NULL     | 5123

但我想要:

SourceTimestamp  | Column01 | Column02
11.12.2017 13:34 | 4545     | 6767
11.12.2017 13:35 | 4456     | 5554
11.12.2017 13:36 | NULL     | 6664
11.12.2017 13:37 | 6233     | 5123

问题是我无法控制的 lambda 表达式循环,我不知道如何处理这个问题。我只需要获取一条订阅消息,将它们声明到列变量并将它们添加到数据库中,但这对我来说似乎有点棘手,而且由于我缺乏 C# 经验,我似乎无法解决问题。欢迎提出建议或其他解决方案。提前致谢。

【问题讨论】:

  • 你能在打印的地方添加第一段代码的输出吗:{0}: {1}, {2}, {3}
  • 如果我没记错的话,您遇到问题是因为您在 switch 语句中使用了 item.DisplayName 而不是 value.DisplayName
  • 我想使用value.DisplayName 之类的东西,但没有这样的东西。只有item.DisplayName 能够迭代,我不确定如何迭代。我只是对这个脚本的迭代感到困惑。
  • 我明白了,现在我明白发生了什么。我不认为你可以在这个方法中做到这一点,因为这似乎是为每一行执行的。但是您想将行组合在一起。

标签: c# entity-framework opc opc-ua


【解决方案1】:

对于数据记录,我只是创建一个循环,读取值,将它们写入数据库,稍等片刻,重复。

那么所有的值都有相同的时间戳。

ps:有些人可能会先使用 RegisterNodes,但这不是必需的!

pps:这里有一些代码。

```

        Console.WriteLine("5a - Read values at an interval of 1 second, for 20 seconds.");

        var readValueIds = new ReadValueId[]
        {
            new ReadValueId{ NodeId= NodeId.Parse("i=2258"), AttributeId = Attributes.Value }, // column 0
            new ReadValueId{ NodeId= NodeId.Parse("i=2258"), AttributeId = Attributes.Value }, // column 1
        };

        var cts = new CancellationTokenSource(20000);
        while (!cts.IsCancellationRequested)
        {
            var resp = session.Read(null, 0, TimestampsToReturn.Both, readValueIds, out DataValueCollection results, out DiagnosticInfoCollection infos);
            Console.WriteLine($"ts:{results[0].SourceTimestamp}, c0: {results[0].Value}, c1: {results[1].Value}");
            await Task.Delay(1000);
        }

```

【讨论】:

  • 循环会是什么样子?它是在OnNotification 函数的外部还是内部?问题是OnNotification 像@gldraphael 所说的那样为每一行调用。我应该只创建一个全局列表来添加项目并将这些项目推送到数据库吗?
  • 无订阅或 OnNotification。只是 session.Read()
  • 你是我的英雄!
【解决方案2】:

Ii 似乎每个“MonitoredItem”在每个事件的队列中只有一个值。 这就是你得到的原因

Column01: 4545, 11.12.2017 13:34, Good
Column02: 6767, 11.12.2017 13:34, Good
Column01: 4456, 11.12.2017 13:35, Good 
Column02: 5554, 11.12.2017 13:35, Good 
Column02: 6664, 11.12.2017 13:36, Good
Column01: 6233, 11.12.2017 13:37, Good 
Column02: 5123, 11.12.2017 13:37, Good

作为输出。 MonitoredItem 似乎有一个唯一标识符:CientHandle。

因此,在您的事件处理程序中,您必须使用该标识符测试现有 dbName 对象的数据上下文并更新该对象(如果存在)。如果不存在,则使用要更新的标识符创建一个新的 dbName 对象。

【讨论】:

  • 你能展示一些示例代码吗?因为我不确定如何处理带有标识符的事件处理程序?
  • 看起来您已经选择了 Andrew 的答案,但我看不出它是否适合您的问题。
  • 结果恰到好处。我有另一种将数据插入数据库的方法。
猜你喜欢
  • 2011-01-20
  • 2017-02-18
  • 2016-09-20
  • 2020-07-24
  • 1970-01-01
  • 2020-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多