Linq provider for Pi (LinqToPi)

Discussion created by MichaelvdV@Atos on Feb 13, 2009
Latest reply on Apr 19, 2010 by spilon

I'm currently developing a Linq provider for Pi (as a side/hobby project). I was wondering if anyone else has done or attemted this. I am calling it 'LinqToPi' (no surprises there...).


I would like to know if you see the advantage of such a provider. I think it will make things a lot more easy! I'm quite excited about it. Please let me know! If you have any suggestions, please also let me know!


For those of you who are not familiar with LINQ:


Language Integrated Query (LINQ, pronounced "link") is a Microsoft.NET Framework component that adds native data querying capabilities to .NET languages.


Microsoft LINQ defines a set of query operators that can be used to query, project and filter data in arrays, enumerable classes, XML, relational database, and third party data sources. While it allows any data source to be queried, it requires that the data be encapsulated as objects. So, if the data source does not natively store data as objects, the data must be mapped to the object domain. Queries written using the query operators are executed either by the LINQ query processing engine or, via an extension mechanism, handed over to LINQ providers which either implement a separate query processing engine or translate to a different format to be executed on a separate data store (such as on a database server as SQL queries). The results of a query are returned as a collection of in-memory objects that can be enumerated using a standard iterator function such as C#'s foreach.


[Source: http://en.wikipedia.org/wiki/Language_Integrated_Query]




The goal is to create a LINQ provider for PI. At the first stage I was using PISDK calls to get the data from the PI system, but, after a few attempts I switched to OleDB.


A few examples:


Getting all snapshot values, with corresponding description and engunits:


PiData data = new PiData("nlms025", "piadmin", Console.Out);


            var points = from p in data.Points
                         join s in data.SnapShots
                            on p.Tag equals s.Tag


                         select new { Tag = p.Tag, Descriptor = p.Descriptor, SnapShot = s.Value };


            foreach (var p in points)
                Console.WriteLine(p.Tag + " " + p.Descriptor + " " + p.SnapShot);


Getting all users with corresponding group:


PiData data = new PiData("nlms025", "piadmin", Console.Out);


            var users = from u in data.Users
                        join m in data.UserMemberships
                        on u.Name equals m.UserName
                        select new { Name = u.Name, Group = m.GroupName };


            foreach (var u in users)
                Console.WriteLine(u.Name + " " + u.Group);


Getting all product versions:


            var versions = from v in data.ProductVersions
                           select v;


            foreach (var v in versions)
                Console.WriteLine(v.Item + " " + v.Version + " " + v.Descriptor);


Getting first 5 values of tags starting with 'SIN', with good values:


 var values = (from v in data.ArchiveData
                          where v.Tag.StartsWith("SIN")
                                && v.Time > DateTime.Now.AddHours(-5)
                                && v.Status == 0
                          select v).Take(5);


            foreach (var v in values)
                Console.WriteLine(v.Tag + " " + v.Value);


Getting first 20 messages from the messagelog, and insert a new item:


var messages = (from m in data.MessageLog
                            select m).Take(20);


            foreach (var m in messages)
                Console.WriteLine(m.Id + " " + m.Source + " " + m.Message);


            data.MessageLog.Insert(new PiLogItem() { Message = "Hello Pi, from LinqToPi" });


These are just a few examples of what's possible. These examples are already working in the current version. At the moment I am working on updating, inserting and deleting data on the Pi server.


The result from the LINQ queries are data classes like:


    public partial class PiValue
        public string Tag { get; set; }
        public DateTime Time { get; set; }
        public int Status { get; set; }
        public double? Value { get; set; }
        public bool? Questionable { get; set; }
        public bool? Substituted { get; set; }
        public bool? Annotated { get; internal set; }
        public string Annotations { get; set; }


As you can see, the classes are partial (so they can be extended), and are DataContracts. So, the values can be serialized easily (to disk), or to send over a WCF service (for use in your Silverlight/other client applications).