46
The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc.

The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Embed Size (px)

Citation preview

Page 1: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

The Weakest LINQ: Querying the AutoCAD® Database

James E. JohnsonSoftware Developer CaptiveAire Systems Inc.

Page 2: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Topics this session will be cover...

LINQ syntax and basics Querying a drawing database using LINQ. Queries on entities and properties. Enumerable generic collections Anonymous methods Anonymous types. Predicate delegates LINQ Lambda expressions. Creating Extension Methods

Page 3: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Questions...

Using LINQ ?

Using Generic List<T> ?

Use Anonymous methods ?

Use Anonymous type “var” ?

Using delegates ?

Using Object Initializers ?

Page 4: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

What is LINQ ("Language Integrated Query")?

LINQ is a .NET programming model that adds querying capabilities to .NET programming languages.

“Language Integrated Query” designates that these query capabilities are accessible within the programming language(e.g., C#, Visual Basic).

LINQ is available with .NET framework version 3.0 and newer.

LINQ defines a standard set of query operators that can be used to query objects and filter datasources.

Page 5: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

LINQ...

C# VB.NET OTHER...

.NET LINQ (Language Integrated Query)

Standard Query

Operators

LINQ To SQL

PROVIDER

LINQ To XML

PROVIDER

.NET Languages

ObjectsRelational Databases XML

Querying

Drawing databas

e objects

LINQ Namespace in System.Core

Page 6: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

LINQ basics...var layernames =

from oid in lt.Cast<ObjectId>() select ((LayerTableRecord) tr,GetObject(oid, OpenMode.ForRead, false)).Name;

var layernames = lt.Cast<ObjectId>() .Select<ObjectId, string> (oid =>

{ return ((LayerTableRecord)tr.GetObject(oid, OpenMode.ForRead, false)).Name; }

Query Expressions

Extension Methods

Local Variable Type Inference

Lambda Expressions

Statement Expression

var dbObjCollection = from oid in btr.Cast<ObjectId>() select new {

DBObj = (DBObject)tr.GetObject(oid, OpenMode.ForRead, false)};

Anonymous types

Object Initializers

Page 7: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Linq basics VB

Dim layernames As List(Of String) = lt.Cast(Of ObjectId).Select(Of LayerTableRecord) _ (Function(oid) DirectCast(tr.GetObject(oid, OpenMode.ForRead, _ False),LayerTableRecord)) _ .Where(Function(ltr) (ltr.IsFrozen)).Select(Function(ltr) (ltr.Name)).ToList()

Dim layernames As List(Of String) = (From oid In lt.Cast(Of ObjectId)() _ Select DirectCast(tr.GetObject(oid, OpenMode.ForRead, False), _ LayerTableRecord).Name) .ToList()

Dim dbObjCollection = From oid In btr.Cast(Of ObjectId)() _ Select New With {.DBObj = _ DirectCast(tr.GetObject(oid, OpenMode.ForRead, False), DBObject)}

Query Expressions

Local Variable Type Inference

Lambda Expressions

Anonymous types

Object Initializers

Extension Methods

Page 8: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

LINQ basics... Query expressions from... where...select

Extension methods .select .orderBy .where .Any

Local variable type inference var dbTxt = ............

Dim dbTxt = ............

Lambda Expressions Func<Point3d, bool> pFiltX = p => (p.X > 4.0);

Function(p) (p.X > 4.0)

Anonymous types new { ............ }

New With { ............ }

Object Initializers new pointObj { X = 1, Y = 2}

New pointObj With { .X = 1, .Y = 2}

Page 9: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Reasons to use LINQ...

Strongly typed arguments and results.

Standard query syntax.

Fully extensible.

Intellesence

Easy to read and maintain.

Page 10: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Visual Studio project requirements

To get started with LINQ, your project needs to have its target framework set to .NET Framework 3.0 or newer.

Add using statements in the class…using System.Collections;using System.Collections.Generic;using System.Linq;using System.Linq.Expressions;

Page 11: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Querying the AutoCAD® Database

Customizing for AutoCAD® applications often requires adding, modifying and removing drawing entities using selection sets or other ways of collecting drawing objects.

Every AutoCAD® Drawing has a database that contains tables (e.g. blocktable, layertable etc) and Dictionaries that can be retrieved as arrays or as a generic List<T> which are both enumerable.

Managing collections is typically done using common looping functions (e.g. For, ForEach etc) to step through collections of entities.

Enumerable collections can be queried using LINQ.

Page 12: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Querying the AutoCAD® Database Examples using foreach to step through the drawings layertable and using a

LINQ query with an anonymous method statement……

VIEW CODE

Page 13: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Query Syntax

LINQ query expressions are written in a declarative query syntax that is similar to SQL statements and was introduced in C# 3.0.

LINQ Comprehension Query Syntax (or just Query Syntax)

LINQ Method Query Syntax (or DOT Syntax)

var layernames = from oid in lt.Cast<ObjectId>() select ((LayerTableRecord) tr,GetObject(oid, OpenMode.ForRead, false)).Name;

var layernames = lt.Cast<ObjectId>() .Select<ObjectId, string> (oid =>

{ return ((LayerTableRecord)tr.GetObject(oid, OpenMode.ForRead, false)).Name; }

Page 14: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

What are Generics?

The term "generic" is a common term for describing something that is not a brand name. Medicine prescriptions may be filled using a “generic” version.

In programming “generic” can refer to a class that is not forced to any specific Type.

Func<T, T> List<T> Dictionary<T>Queue<T>IEnumerable<T>

List<string> layernames = new List<string>;

Generic classes are created to allow definition of collections without specifying the actual types used.

Page 15: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Arrays, Generic List<T> and IEnumerable

LINQ extension methods for standard query operators add query functionality to the existing System.Collections.IEnumerable and System.Collections.Generic.IEnumerable<T> types.

The Array class provides methods for creating, manipulating, searching and sorting arrays, it implements the IEnumerable interface.

ArrayList layernames = new ArrayList();

The List<T> class represents a strongly typed list of objects that can be accessed by index and is the generic equivalent of the ArrayList class.

Page 16: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

List<T> vs. ArrayList()...

UnBoxing the opposite of boxing. A reference is retrieved to the value type (data fields) contained within an object. The common language runtime first ensures that the reference type variable is not null and that it refers to an object that is a boxed value of the desired value type. If the types match, then a pointer to the value type contained inside the object is returned.

Boxing is the process of converting a value type to a reference type. Memory is allocated from the heap. The amount of memory allocated is the size required by the value type plus any additional overhead. The values are copied to the newly allocated heap memory. The address of the object is returned as the reference type.

A Generic List<T> is strongly typed so does not require BOXING and UNBOXINGwhen enumerating the items.

Page 17: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

IEnumerable<T> and IQueryable<T> interfaces The generic interface IEnumerable<T> is defined for generic

types to iterate the elements of a collection by exposing the enumerator, which supports a simple iteration of a specific type.

Any data type that implements the IEnumerable<T> interface can directly serve as a source for query expressions with LINQ.

The IQueryable<T> interface is primarily used for query providers and inherits the IEnumerable<T> interface so that a query can be enumerated.

Page 18: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Standard Query operators

Standard Query Operators are the base of LINQ. Extension methods that implement the IEnumerable<T> interface Operator Type Operator Name

Aggregation Aggregate, Average, Count, LongCount, Max, Min, Sum

Conversion Cast, ConvertAll, OfType, ToArray, ToDictionary, ToList, ToLookup, ToSequence

ElementDefaultIfEmpty, ElementAt, ElementAtOrDefault, First, FirstOrDefault, Last, LastOrDefault, Single, SingleOrDefault

Equality EqualAll

Generation Empty, Range, Repeat

Grouping GroupBy

Joining GroupJoin, Join

Ordering OrderBy, ThenBy, OrderByDescending, ThenByDescending, Reverse

Partitioning Skip, SkipWhile, Take, TakeWhile

Quantifiers All, Any, Contains

Restriction Where

Selection Select, SelectMany

Set Concat, Distinct, Except, Intersect, Union

Page 19: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

LINQ Query Syntax Keywords

Clause Description

from Query syntax expressions must start with a ‘from’ clause. Specifies the data source and a range variable that represents each element in the source.

where Used in an expression to specify which elements will be returned. Applies a predicate to each element in the source specified in the ‘from’ clause range variable.

select Specifies the type of values in the returned sequence when the query is executed.

group Returns a sequence that contains none or many items that match a specified key value.

into Used to create an identifier that can serve as a reference to the results of a join, group or select clause.

orderby Sorts query results in ascending or descending order based on the default comparer for the element type.

join Joins two data sources based on an equality comparison between two specified matching criteria.

let Introduces a range variable to store sub-expression results in a query expression.

in Contextual keyword in a join clause.

on Contextual keyword in a join clause.

equals Contextual keyword in a join clause.

by Contextual keyword in a group clause.

ascending Contextual keyword in an orderby clause.

descending Contextual keyword in an orderby clause.

Page 20: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Anonymous Types

LINQ is data driven programming which uses static structures instead of objects, anonymous types are used to allow new structures to be defined “inline”.

Example creates an “inline” anonymous type with a property named “DBObj” returning DBObjects found to dbObjCollection…

var dbObjCollection = from oid in btr.Cast<ObjectId>() select new {

DBObj = (DBObject)tr.GetObject(oid, OpenMode.ForRead, false) };

var dbTxt = from obj in dbObjCollection where (obj.DBObj.GetType() == typeof(DBText))

select obj.DBObj;

List<DBText> dwgDBText = dbTxt.Cast<DBText>().ToList()

Page 21: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Anonymous Type “Var”

The “var” keyword may remind you of less strongly typed languages like VB6. Most languages now use strongly typed objects.

The “var” keyword tells the compiler to infer the type of the variable from the static type of the expression used to initialize the variable.

LINQ determines the type at compile time and VB6 determined the type at runtime.

var dbTxt = from obj in dbObjCollection where (obj.DBObj.GetType() == typeof(DBText))

select obj.DBObj;

Page 22: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Use “Var” or specify Type You can stick to Strongly typing:

The result type of “DBText” is specified so the result type of the query must be declared, this is a strongly type a query result.

Instead of:

The “var” local type inference is used to let the compiler determine the type.

IEnumerable<DBText> dbTxt = from obj in dbObjCollection

where (obj.DBObj.GetType() == typeof(DBText)) select (DBText)obj.DBObj;

var dbTxt = from obj in dbObjCollection where (obj.DBObj.GetType() == typeof(DBText) select (DBText)obj.DBObj;

Page 23: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Delegates and Anonymous methods

Delegates are used to pass methods as arguments to other methods.

A class or a method can be created for using a delegate.

Anonymous methods were introduced in C# 2.0 which allows defining anonymous (nameless) method to be called by a delegate.

delegate void sampDelegate(string s);static public void sampleDelegate(){ Editor ed = AcadApp.DocumentManager.MdiActiveDocument.Editor; //anonymous delegate sampDelegate annonyDel = delegate(string s) { ed.WriteMessage(s); }; annonyDel("I am anonymous");

//lambda delegate sampDelegate lambdaDel = (x) => { ed.WriteMessage(x); }; lambdaDel("I am a Lambda expression");}

Page 24: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Anonymous method example:

VIEW CODE

Page 25: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Generic Delegate System.Func

The generic delegate System.Func can be used to define a delegate when needed without defining an explicit delegate type declaration.

The TArg0, TArg1, TArg2, and TArg3 parameters are argument types and the TResult parameter represents the result type.

Func<Point3d, bool> pointFilterX = p => (p.X > 4.0);

Func<TResult>();

Func<TArg0, TResult>(TArg0 arg0);

Func<TArg0, TArg1, TResult>(TArg0 arg0, TArg1 arg1);

Func<TArg0, TArg1, TArg2, TResult>(TArg0 arg0, TArg1 arg1, TArg2 arg2);

Func<TArg0, TArg1, TArg2, TArg3, TResult> (TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3);

Page 26: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Generic Delegate System.Func Example:

VIEW CODE

Page 27: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Generic Delegate System.Action System.Action is a set of predefined delegates that encapsulate

up to 4 arguments with no return values…

static public void actionSamp(){ Editor ed = AcadApp.DocumentManager.MdiActiveDocument.Editor;

Point3d newpoint = new Point3d(4.0, 4.0, 0.0); Action<Point3d, string> pointAction = (p, s) => ed.WriteMessage(s + p.X.ToString()); //execute action pointAction(newpoint, "value of X:");

}

Page 28: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Predicate Delegates

A predicate is a function that returns true or false and can be used to filter the results of a query.

A predicate defines a set of criteria, and determines if a specified object meets those criteria.

Predicates take advantage of the generic features introduced in the .NET Framework 2.0.

Some of the methods that use an instance of the System.Predicate delegate to perform their tasks are: Exists, Find, FindAll, FindIndex, FindLastIndex, FindLast, RemoveAll and TrueForAll.

The best way of thinking about predicates is to think about them as filters, that will evaluate to True or False.

Page 29: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Predicates Examples: Example searches for layers containing the string “Layer” in the delegate

used as the predicate:

VIEW CODE

Page 30: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

MinX = objExtents.Min<Extents3d>(ext => ext.MinPoint.X);MinY = objExtents.Min<Extents3d>(ext => ext.MinPoint.Y);MinZ = objExtents.Min<Extents3d>(ext => ext.MinPoint.Z);

Lambda Expressions

Query operators provide functionality to perform filtering, projection, or extraction and build on the concept of lambda expressions.

Lambda expressions are an evolution of anonymous methods introduced in .NET 2.0.

The ‘=>’ symbol is used in lambda statements stating that the defined object “goes into” the expression…

Func<Point3d, bool> pointFilterX = p => (p.X > 4.0);Func<Point3d, bool> pointFilterY = p => (p.Y > 4.0);

Page 31: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Lambda Expressions

Nested lambda example (‘ent’ of type Entity can be used in second inline lambda statement):

Lambda expressions used in delegates:

Expressions or statement blocks can be contained in Lambda expressions.

.Where<Entity>(ent => layernames.Any<string>(lay => lay == ent.Layer))

string[] parts = { "Bolt", "Nut", "Flange","Pipe", "Bar", "Cylinder"};Func<string, bool> filt = s => s.Length > 5;Func<string, string> val = s => s;Func<string, string> sel = s => s.ToUpper();IEnumerable<string> query = parts.Where(filt).OrderBy(val).Select(sel);

a => 3.1416 * a // Expressiona => {return 3.1416 * a;} // Statement

Page 32: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Lambda Expressions

Delegates and lambda expressions are equivalent.

Func<int> funcDelegate = delegate(int a) { return a * 3.1416; };

Func<int> lambda = a => a * 3.1416;

Page 33: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Lambda Expressions

VIEW CODE

Page 34: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Expression Trees

LINQ provides a simple syntax for translating code into a data structure called an expression tree.

The System.Linq.Expressions namespace defines a generic type, Expression<T>, where T is the type of the delegate that defines the expression's signature.

Expression trees are used for creating LINQ Providers to extend querying to multiple data structures.

Page 35: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Expression Trees

Expression trees are created in-memory out of lambda expressions and then allow manipulation or inspection of the expression as data. 

VIEW CODE

Page 36: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Object Initializers

A feature added in C# 3.0 is the syntax for object initializers.

Allow initializing an object by creating the object instance.

Assign values to one or more properties in a single sentence.

Initialize a collection with a set of values to add in a single expression similar to how it is done with arrays.

var dbObjCollection = from oid in btr.Cast<ObjectId>() select new {

DBObj = (DBObject)tr.GetObject(oid, OpenMode.ForRead, false)};

Page 37: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Object Initializers

Anonymous types can be populated using object initializers.

var dwgInfo = new { Description = "New Drawing", DrawnBY = "James", Date = "12/2/2009", DwgNumber = "123456", RevisionNo = "A" };

Page 38: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Object Initializers This example illustrates using object initializers to set the values

to instances of the class and then adding those objects to a generic list.

VIEW CODE

Page 39: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Extension Methods

Allow the creation of methods on an existing “Type” creating the illusion of new methods.

With extension methods developers can augment the “Type” with new methods to provide their own methods.

Extension methods are defined in static classes as static methods.

In C#, extension methods are indicated by the “this” modifier which must be applied to the first parameter of the extension method.

Add methods to a class compiled outside of the current assembly that can not be changed.

Page 40: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Extension Methods Extension methods are resolved at compile-time.

Namespaces imported with C#’s using statement or VB’s Import statement are defined by static classes and brought into scope.

LINQ standard query operators are extension methods in the System.Linq namespace, these extension methods extend IEnumerable<T> and IQueryable<T>.

Most of the standard query operators extend from the IEnumerable<T> interface, these types will get the standard query operators by adding the using statement ‘using System.Linq;’ in C#.

Extension methods show up in Intellesense

Page 41: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Extension Methods The type of the first parameter of an extension method indicates

what type the extension applies to.

VIEW CODE

Page 42: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Deferred Query Evaluation LINQ standard query operators return elements when

enumerated not when declared.

Operators do no work UNTIL the query requests an element then suspends until the next element is requested.

Deferred evaluation allows queries to be kept as IEnumerable<T> based values that can be evaluated multiple times, each time yielding potentially different results.

A query can be enumerated immediately, using ToList() or ToArray() which both will enumerate the entire sequence returning a result.

Page 43: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Deferred Query Evaluation Example uses one of the previous examples to get text entities

then modifies the “Last” text entity found and runs the query again…

VIEW CODE

Page 44: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

LINQ Providers

LINQ works between the programming language and the data source that queries are applied against.

A provider works between the LINQ engine and the data source to extend the query functionality on the data source.

Page 45: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc

Thanks for Attending…

Page 46: The Weakest LINQ: Querying the AutoCAD® Database James E. Johnson Software Developer CaptiveAire Systems Inc