Geeks With Blogs
Rohit Gupta Engaging talk on Microsoft Technologies ....My Resume

Some of the new Features in EF v4 are :

context.ContextOptions.LazyLoadingEnabled is “true” by default.
What this means is that if you access a Navigation Property (which returns either a EntityCollection or a EntityReference) of an Entity and if that Navigated Entity (or Entity collection) is not found in the ObjectContext then the ObjectContext automatically loads it when the NavigationProperty is accessed. This means additional round trip to the database for each Navigated entity.
If you need to turn off this LazyLoadingEnabled flag on the ObjectContext set the LazyLoadingEnabled flag in the OnContextCreated() partial method of the PEFEntities partial class you created like so :

   1: public partial class PEFEntities
   2: {
   3:     partial void OnContextCreated()
   4:     {
   5:         this.ContextOptions.LazyLoadingEnabled = false;
   6:     }
   7: }

ObjectSet<TEntity>
In EntityFramework v4.0 when you execute a ObjectQuery<> it returns a ObjectSet of Entities. In earlier versions of Entity Framework, the ObjectQuery when executed returned a ObjectQuery itself which we could then iterate through to get results.

context.ExecuteStoreCommand

This command can be used to execute SQL/PSQL commands that don't return any values for e.g. insert/delete statements.

   1: using (var context = new EFRecipesEntities())
   2: {
   3:     context.ExecuteStoreCommand("delete from chapter10.Product");
   4:     context.ExecuteStoreCommand("insert into chapter10.Product values ('Chai', 'Beverage')");
   5: }

context.ExecuteStoreQuery<TElement>
If you need to execute a SQL/PSQL that returns record sets then use context.ExecuteStoreQuery<TElement> where TElement can be an existing Entity in the CSDL of the EDMX file, or if the result does not map to an existing Entity in the CSDL then use context.ExecuteStoreQuery<DbDataRecord> to iterate over the columns of the returned results manually using indexers on DbDataRecord to access column values. Note that context.ExecuteStoreQuery<> returns a ObjectResult<TElement> which be iterated over only once as opposed to ObjectSet<T> or ObjectQuery<T> which can be iterated over multiple times.

   1: using (var context = new EFRecipesEntities())
   2: {
   3:     string sql = "select * from Chapter3.Student where Degree = @Major";
   4:     var args = new DbParameter[] { new SqlParameter { ParameterName = "Major", Value = "Masters" } };
   5:     var students = context.ExecuteStoreQuery<Student>(sql, args);
   6: }


context.Translate<>
EF v4 does not provide a DIRECT way to iterate over Multiple result sets returned from a Stored Proc/ SQL Query. One solution is to use SqlCommand object to execute and return a SQLDataReader which contains multiple result sets and pass this datareader to context.Translate<> method which materialzes the datareader results into Entity objects. If you use the correct overload of context.Translate<>(reader, entitySetName, MergeOption) then Translate also fixes relationship spans automatically (i.e. fixes associations between related entities automatically).
Here is an example :

   1: using (var context = new EFRecipesEntities())
   2: {
   3: var cs = @"Data Source=.;Initial Catalog=EFRecipes;Integrated Security=True";
   4: var conn = new SqlConnection(cs);
   5: var cmd = conn.CreateCommand();
   6: cmd.CommandType = System.Data.CommandType.StoredProcedure;
   7: cmd.CommandText = "Chapter3.GetBidDetails";
   8: conn.Open();
   9: var reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
  10: var jobs = context.Translate<Job>(reader, "Jobs",
  11: MergeOption.AppendOnly).ToList();
  12: reader.NextResult();
  13: context.Translate<Bid>(reader, "Bids", MergeOption.AppendOnly).ToList();
  14:     foreach (var job in jobs)
  15:     {
  16:         Console.WriteLine("\nJob: {0}", job.JobDetails);
  17:         foreach (var bid in job.Bids)
  18:         {
  19:         Console.WriteLine("\tBid: {0} from {1}",
  20:         bid.Amount.ToString("C"), bid.Bidder);
  21:         }
  22:     }
  23: }
If we do not use the correct overload of context.Translate<> then, in the above example the Bids would never get materialized into objects since there will not exist any association between jobs and bids. Also note that we do not need to call .ToList() on the first context.Translate<Job>() method before we can call reader.NextResult(), since context.Translate<> merely returns ObjectResult<Job> which needs to be completely iterated over before NextResult() call can succeed.
Translate() requires that the DbDataReader have columns that match each property on the entity. This matching is done using simple name matching. If a column name can’t be matched to a property, Translate() will fail.

DefaultIfEmpty() is now supported with EF v4.

In earlier versions of Entity Framework DefaultIfEmpty() method was not supported on ObjectQueries hence it was difficult to create LinqToEntities queries which was a Left JOIN across collections. In EF v4 we surely have this capability, so left joins are easier to implement and use in LinqToEntities. Here is an example:
   1: var products = from p in context.Products
   2:     join t in context.TopSellings on
   3:     p.ProductId equals t.ProductId into g
   4:     from tps in g.DefaultIfEmpty()
   5:     orderby tps.Rating descending
   6:     select new
   7:     {
   8:         Name = p.Name,
   9:         Rating = tps.Rating == null ? 0 : tps.Rating
  10:     };
CreateSourceQuery()
CreateSourceQuery() to create a ObjectQuery() from a EntityCollection or EntityReference to delay load Navigation properties of Entities.
If a Entity “address” has a Navigation Property which returns a EntityReference  “contact” or EntityCollection “Streets” and if LazyLoadingEnabled =  false, then inorder to insure that the EntityReference/EntityCollection is delay loaded we can either call the .Load() method on the
“address” entity’s navigation property. The other option is to call CreateSourceQuery() on the navigation property and then access the EntityReference or iterate over the EntityCollection.
The advantage of using CreateSourceQuery() is that we can add further QueryBuilder methods like “Include” to the ObjectQuery<> created by the CreateSourceQuery() call. for e.g. address.Contact.CreateSourceQuery().Include(“Orders”) will not only load the contact EntityReference, but it will also load all Orders for the contact.
The other advantage of CreateSourceQuery() is that we can use filters to get only certain entries from the EntityCollection (as shown below).
Yet another advantage of using CreateSourceQuery() is that we can attach range of Entities to a EntityCollection, instead of attaching 1 entity at a time.
   1: var cust=context.Contacts.OfType<Customer>().First(); 
   2: var sq = cust.Reservations.CreateSourceQuery().Where(r => r.ReservationDate > new DateTime(2008,1,1)); 
   3: cust.Reservations.Attach(sq); 
Gotchas with using the .Include() Query Builder method:
    If the query on which the .Include() builder method has been used does projections or group joins then the Include with be ignored. Group Joins changes the result type of the query hence the Include() is ignored.
    Thus Include applies only to final query results. if Include is used in a subquery, join, or nested “from” clause it is ignored.
    Include() method is a extension method only on the ObjectQuery<T>. Thus if you need to execute the Include() extension method against a IQueryable<T> then we need to cast it to ObjectQuery<T> first.
    The Query Path used within a Include() must begin from a Navigation property of the Entity on which the Include is being used.

IsLoaded Property, Clear() and Load() methods.
When you call Clear() method on Navigation Property which is a EntityCollection, then the cleared entities do still remain in the ObjectContext, its just that they are no longer connected to the parent entity. for e.g. order.OrderItems.Clear() will empty the OrderItems collection of the order Entity, however the OrderItem Entities themselves will still remain in the ObjectContext. Thus if you need to reconnect the OrderItem entities for the order then we need to call order.OrderItems.Load(MergeOption.OverwtiteChanges) instead of order.Orderitems.Load() since the default merge option is MergeOption.AppendOnly.

If you are manually doing deferred loading then always used .IsLoaded Property on the Entity you are trying to Load before explicitly defer loading of the Entity.
Another thing to note about the IsLoaded Property is that say for e.g. for Order with OrderId 1 there are no OrderItems. Thus when you call .Load() on the order.OrderItems.Load() then the OrderItems collection will be null, however note that the .IsLoaded property of OrderItems will be true.

When you use the CreateSourceQuery() method to grab the query for loading the entity or entity collection, Entity Framework will not set IsLoaded when the query is executed

If a parent Entity has been Loaded using a specific MergeOption then all the navigation entities must also be loaded with the same MergeOption else the deferred Loading of the Navigation entities will fail.

Relationship-span and Associations
When EF loads an Entity it also loads any “associations” that are 0..1 or 1..1.”associations” are first-class objects like entities. EF creates 3 ObjectStateEntries on ObjectStateManager, 1 for the Entity, 1 for the Association and 1 for the Stub for the other end of the association that is not yet loaded. The stub has a valid EntityKey even though the entity itself has not yet been loaded.
When that other entity is loaded the first entities stub is automatically populated with this other entity which just got loaded and thus completes the association.
This automatic loading of the stub entity is called relationship-span.

QueryView… EntitySQL queries written in the MSL … when to use QueryViews:
QueryViews can be very handy when you need to create Entities using more complex Filter conditions.
Finally to be able to use these Entities created using QueryViews to be updateable use Stored procedures to map to the  Insert, Update and Delete Functions of each entity being created using the QueryView.

Using ObjectStateManager to retrieve Entities from the ObjectContext that not yet saved to the database:
Use the following code to retrieve all Entities from the OSM (ObjectStateManager) that are not in the Detached state (i.e. in the Added, Modified, Deleted or Unchanged states):

   1: public static class StateManagerExtensions
   2: {
   3: public static IEnumerable<T> GetEntities<T>(this ObjectStateManager manager)
   4:     {
   5:     var entities = manager
   6:     .GetObjectStateEntries(~EntityState.Detached)
   7:     .Where(entry => !entry.IsRelationship && entry.Entity != null)
   8:     .Select(entry => entry.Entity).OfType<T>();
   9:     return entities;
  10:     }
  11: }

Note that when you run queries directly against the ObjectContext to get Entities ( for e.g. context.Technicians.Include(“ServiceCalls”), they return only entities that currently exist in the database. It is important to note that when you add or delete entities from the object context, these changes are not reflected in results of queries against the object context (context.Technicians). These queries represent entities as they exist in the database, not what currently exist in the object context.

Attach() vs AddObject().
We can use AddObject() on the EntitySet or the ObjectContext to add new Entities to the collection. However we can also use Attach() to add new entities to the collection. However when adding Entities using Attach is a 2 step process. First we need to call EntitySet.Attach() to attach the entity to the ObjectContext. However after calling Attach() the EntityState of this entity is still “Unchanged”, thus we need to change the EntityState of this entity to Added using the ObjectStateManager by calling context.ObjectStateManager.ChangeObjectState(entity, EntityState.Added).

Model Functions:
Model functions are functions defined using EntitySQL in the Conceptual Model (CSDL of the EDMX file). An Example of a Model Function (defined as a child element of the <Schema Namespace="EFRecipesModel"> element in the CSDL):

   1: <Function Name="GetInvoices" ReturnType="Collection(EFRecipesModel.Invoice)" >
   2: <Parameter Name="invoices" Type="Collection(EFRecipesModel.Invoice)">
   3: </Parameter>
   4: <DefiningExpression>
   5: Select VALUE i
   6: from invoices as i where i.Amount > 300M
   7: </DefiningExpression>
   8: </Function>

=========================================================
Note the distinction of Model Functions….these are defined in the Conceptual Model i.e. CSDL section of the EDMX file, whereas the DefiningQuery is defined in the SSDL section of the EDMX file and uses TSQL, if querying SQL Server, and return Entities from the Store layer.
An Example of a DefiningQuery is :

   1: <EntitySet Name="vOfficeAddresses"
   2:  EntityType="BreakAwayModel.Store.vOfficeAddresses" store:Type="Tables"
   3:  store:Schema="dbo" store:Name="vOfficeAddresses">
   4:    <DefiningQuery>
   5:      SELECT
   6:       [vOfficeAddresses].[FirstName] AS [FirstName],
   7:       [vOfficeAddresses].[LastName] AS [LastName],
   8:       [vOfficeAddresses].[addressID] AS [addressID]
   9:      FROM [dbo].[vOfficeAddresses] AS [vOfficeAddresses]
  10:    </DefiningQuery>
  11: </EntitySet>
=========================================================
One can also define Custom functions in the Store Layer (SSDL section of EDMX file) which are treated as Stored procedures whose return types can be scalar properties, ComplexTypes or Entities defined in the Conceptual layer. An example of a Custom function in SSDL (effectively seen as Sproc in the Model browser), defined as child element of the <Schema> element:
   1: <Function Name="MembersWithTheMostMessages" IsComposable="false">
   2: <CommandText>
   3: select m.*
   4: from chapter10.member m
   5: join
   6: (
   7: select distinct msg.MemberId
   8: from chapter10.message msg where datesent = @datesent
   9: ) temp on m.MemberId = temp.MemberId
  10: </CommandText>
  11: <Parameter Name="datesent" Type="date" />
  12: </Function>

Here the result of this custom Function is mapped to the Member Entity type in the CSDL.
=========================================================
QueryView is another type of query which is defined in the MSL i.e. mapping layer of the EDMX file. QueryView is written using ESQL, queries the Store layer Entities and returns Conceptual layer Entity. An Example of the Query view:

   1: <EntitySetMapping Name="WebOrders">
   2: <QueryView>
   3: select value
   4: EFRecipesModel.WebOrder(o.OrderId,
   5: o.CustomerName,o.OrderDate,o.IsDeleted,o.Amount)
   6: from EFRecipesModelStoreContainer.WebOrder as o
   7: where (o.OrderDate > datetime'2007-01-01 00:00') ||
   8: (o.OrderDate between cast('2005-01-01' as Edm.DateTime) and
   9: cast('2007-01-01' as Edm.DateTime) and !o.IsDeleted) ||
  10: (o.Amount > 800 and o.OrderDate &lt;
  11: cast('2005-01-01' as Edm.DateTime))
  12: </QueryView>
  13: </EntitySetMapping>

QueryViews come in handy when you need to filter by multiple criteria (as shown above), or you need to implement Table per Hierarchy inheritance when the foreign key defined in the derived tables is not the primary key of the derived table.

Posted on Wednesday, June 23, 2010 7:40 AM | Back to top


Comments on this post: Entity Framework v4 – Tips and Tricks

# re: Entity Framework v4 – Tips and Tricks
Requesting Gravatar...
When you copy content from our book Entity Framework 4.0 recipes, pls at least mention the name of the source where you got these tips.
Left by Zeeshan Hirani on Jul 07, 2010 6:50 PM

# About context.ExecuteStoreQuery<TElement>
Requesting Gravatar...
I got a question for you concerning ExecuteStoreQuery<T> in the case where the result "does not map to an existing Entity".

You said you could use <DbDataRecord> as a type to run this query and iterate through it.

Do you have an example about it should be done ? DbDataRecord is an abstract class of the System.Data namespace of .NET, and can not be iterated since ExecuteStoreQuery requires that "The result type 'System.Data.Common.DbDataRecord' may not be abstract and must include a default constructor."

Any clue or ressource available to help with this ? I've put 2 days making this works, and ressources are really scarce on the Net resolving this matters.
Left by LoganWolfer on Jan 07, 2011 2:37 PM

# re: Entity Framework v4 – Tips and Tricks
Requesting Gravatar...
I get the same error that LoganWolfe does, so an example would be usefull.
Left by Topo on Mar 02, 2011 5:41 AM

# re: Entity Framework v4 – Tips and Tricks
Requesting Gravatar...
I made a mistake, it should been a combination of EntitySQL and context.ObjectQuery(esql) that would do the trick. then you iterate over results using indexers.
Left by Rohit Gupta on Sep 28, 2011 4:12 AM

# question from hfrmobile
Requesting Gravatar...
Maybe the e acute was the problem when posting my previous post?

Original post:
In my experience lazy loading is disabled by default in EF4 ...

Answer by Rohit Gupta:
when i wrote this article, at that time it was enabled by default ( i.e. set to true)
now with EF 4.1 and EF 4.2 LazyLoading is disable by default on the ObjectContext, however it is enabled by default on DbContext (the new class introduced in EF 4.1)

HTH.
Thanks,
Rohit
----

Think this will be helpful for others too.

Regards,
hfrmobile
Left by Harald-René Flasch on Nov 17, 2011 10:33 AM

Your comment:
 (will show your gravatar)


Copyright © Rohit Gupta | Powered by: GeeksWithBlogs.net