繁体   English   中英

通过C#中的OPC UA客户端插入具有ADO.NET实体数据模型的数据库

[英]Insert to Database with ADO.NET Entity Data Model through OPC UA Client in C#

我正在尝试使用来自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,但只能插入不同的行。 所以我在数据库中的Table看起来像这样:

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#的经验,我似乎无法解决问题。 欢迎提出建议或其他解决方案。 提前致谢。

我似乎每个“ 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对象。

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

然后,所有值都具有相同的时间戳。

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);
        }

```

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM