LINQ to Entities


By now, we have seen how to leverage LINQ queries to select data over SQL databases and DataSet instances, using a data-centric approach. Every single query we ran was against a particular data table, with a one-to-one mapping between data tables and query results. However, the real world of enterprise application development requires abstraction from a physical data persistence layer to guarantee maintainability and platform independency.

Whenever we work with an Entity Data Model (EDM), we create an abstraction, modeling entities at a conceptual level rather than at the data level. LINQ to Entities allows querying a list of entities abstracted from the physical data layer, using LINQ syntax. We define entities as instances of entity types (such as Order, Customer, Product, and so on), which are structured and built starting from any kind of persistence layer but independent of it. Entities are grouped into EntitySet objects and can be related to each other through relationships, which are instances of relationship types (such as CustomerOrders, OrderProducts, and so on).

With LINQ to Entities, we can leverage object inheritance and data complexity. For instance, we can have a complex Customer type that includes its Orders as a sequence property, inheriting its base structure from the Contact type. From an entity point of view, we do not care how the Contact, Customer, and Orders of the Customer are brought to us; we care about them only when they are in memory. On the other hand, under the cover, we need a program to query a particular database to extract the content of these entities. Whatever makes the magic is defined by the mapping between .NET classes and the database structure. This mapping is made of a set of files and can be defined using a tool, called with an EDM schema as input, that generates the .NET classes that map to the EDM structure. This tool maps the conceptual layer (entities) with the database physical schema (persistence layer), making the inner workings transparent. We can imagine having a Customer entity, defined starting from a subset of the classic Northwind sample application, like the one defined in Listing 5-33.

Listing 5-33: A handmade Customer entity

image from book
  public partial class Customer {     public string CustomerID {         get { return this._CustomerID; }         set { this._CustomerID = value; }     }     private string _CustomerID = string.Empty;     public string CompanyName {         get { return this._CompanyName; }         set { this._CompanyName = value; }     }     private string _CompanyName = string.Empty;     public string Country {         get { return this._ Country; }         set { this._ Country = value; }     }     private string _ Country = string.Empty; } 
image from book

We defined this entity by hand, and you probably know the effort required to keep each instance of Customer synchronized with a physical data layer, including eventually handling relationships with instances of SalesOrders. To solve this problem, you can use one of the many Object Relational Mapping (ORM) frameworks built on top of .NET, or you can simply base your solution on LINQ to Entities and ADO.NET Entity Framework. If you use LINQ to Entities, you should define any of your entities by using a designer for Visual Studio, or define them manually with a text or XML editor. Whatever technique you use, you must define a set of XML files that describes each Entity, EntitySet, and Association and that maps each of them to corresponding tables and views on a particular data layer. The result of this mapping will be a set of auto-generated classes that define entities such as the Customer shown in Listing 5-33, but with metadata information to influence the behavior of their instances. Listing 5-34 shows how this is done.

Listing 5-34: An ADO.NET Entity Framework auto-generated Customer entity

image from book
   [System.Data.Objects.DataClasses.EntityTypeAttribute(   SchemaName = "NorthwindLib", TypeName = "Customer" )] public partial class Customer : global::System.Data.Objects.DataClasses.Entity {   // ...   [System.Data.Objects.DataClasses.EntityKeyPropertyAttribute()]   [System.Data.Objects.DataClasses.NullableAttribute( false )]   public string CustomerID {     get { return this._CustomerID; }     set {       this.ReportPropertyChanging( "CustomerID",                   this._CustomerID );       this._CustomerID = global::System.Data.Objects.DataClasses.StructuralObject.Set ValidValue(  value, false, 5, true );       this.ReportPropertyChanged( "CustomerID", this._CustomerID );       }   }   private string _CustomerID = string.Empty;   [System.Data.Objects.DataClasses.EdmScalarPropertyAttribute()]   [System.Data.Objects.DataClasses.NullableAttribute( false )]   public string CompanyName {     get { return this._CompanyName; }     set {       this.ReportPropertyChanging( "CompanyName",                   this._CompanyName );       this._CompanyName = global::System.Data.Objects.DataClasses.StructuralObject.Set ValidValue(  value, false, 40, true );       this.ReportPropertyChanged( "CompanyName", this._CompanyName );       }   }   private string _CompanyName = string.Empty;   [System.Data.Objects.DataClasses.EdmScalarPropertyAttribute()]   [System.Data.Objects.DataClasses.NullableAttribute(true)]   public string Country {     get { return this._Country; }     set {       this.ReportPropertyChanging("Country", this._Country);       this._Country = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(   value, true, 15, true);       this.ReportPropertyChanged("Country", this._Country);       }   }   private string _Country; } 
image from book

This second Customer class, shown in Listing 5-34, is broadly decorated with attributes of the System.Data.Objects.DataClasses namespace. These attributes provide information about the entity model, regardless of its database mapping. You can see that they describe relationships between the class properties and the schema model, not the physical database model. Listing 5-35 shows a sample query to select all the instances of Italian customers.

Listing 5-35: A query to select all the Italian customers

image from book
  using (Northwind db = new Northwind( NWIND_CONNECTION_STRING ) ) {   ObjectQuery<Customer> customers = db.CreateQuery<Customer>(     "SELECT VALUE c FROM Customers AS c WHERE c.Country = 'Italy'" );   foreach(Customer c in customers) {     Console.WriteLine( c );   } } 
image from book

As you can see, the query uses an SQL-like syntax that works with typed entities (that is, instances of our Customer type) rather than with tables. A lot of the plumbing code-usually defined to work with databases, invoke specific SQL statements, iterate over records, and so forth-has been moved under the cover. Starting from the previous query, we can see that LINQ works with deferred queries, evaluated when we effectively access them, which are converted to the right extension method for the sequences we are querying. Consider Listing 5-36, which shows the LINQ query against the previously seen sequence of Customers entities.

Listing 5-36: A LINQ query over a sequence of Customers entities

image from book
  using (Northwind db = new Northwind( NWIND_CONNECTION_STRING ) ) {   var customers =     from   c in db.Customers     where  c.Country == "Italy"     select c;   foreach(Customer c in customers) {     Console.WriteLine( c );   } } 
image from book

The result of this query, when it is evaluated, will be the one shown in Listing 5-36. The query expression deferred evaluation will produce it. This approach can be very interesting whenever we define the business layer and the components that need to handle business entities, and handle them independently from the persistence layer and without concern for the real source of entity data sources.

With these concepts, you can make a case for using the capabilities of LINQ to Entities in everyday programming. More details on LINQ to Entities and ADO.NET Entity Framework are provided in the Appendix, “ADO.NET Entity Framework.”




Introducing Microsoft LINQ
Introducing MicrosoftВ® LINQ
ISBN: 0735623910
EAN: 2147483647
Year: 2007
Pages: 78

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net