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

Post on 17-Dec-2015

217 views 1 download

Tags:

transcript

The Weakest LINQ: Querying the AutoCAD® Database

James E. JohnsonSoftware 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

Questions...

Using LINQ ?

Using Generic List<T> ?

Use Anonymous methods ?

Use Anonymous type “var” ?

Using delegates ?

Using Object Initializers ?

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.

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

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

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

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}

Reasons to use LINQ...

Strongly typed arguments and results.

Standard query syntax.

Fully extensible.

Intellesence

Easy to read and maintain.

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;

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.

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

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

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.

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.

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.

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.

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

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.

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()

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;

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;

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

Anonymous method example:

VIEW CODE

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

Generic Delegate System.Func Example:

VIEW CODE

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:");

}

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.

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

used as the predicate:

VIEW CODE

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

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

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;

Lambda Expressions

VIEW CODE

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.

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

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

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

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

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.

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

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

what type the extension applies to.

VIEW CODE

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.

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

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.

Thanks for Attending…