Using DbContext in EF 4.1 Part 3: Finding Entities
The information in this post is out of date.
Visit msdn.com/data/ef for the latest information on current and past releases of EF.
For Finding Entities see https://msdn.com/data/jj573936
Introduction
Version 4.1 of the Entity Framework contains both the Code First approach and the new DbContext API. This API provides a more productive surface for working with the Entity Framework and can be used with the Code First, Database First, and Model First approaches. This is the third post of a twelve part series containing collections of patterns and code fragments showing how features of the new API can be used.
The posts in this series do not contain complete walkthroughs. If you haven’t used EF 4.1 before then you should read Part 1 of this series and also Code First Walkthrough or Model and Database First with DbContext before tackling this post.
Finding entities using a query
DbSet and IDbSet implement IQueryable and so can be used as the starting point for writing a LINQ query against the database. This post is not the appropriate place for an in-depth discussion of LINQ, but here are a couple of simple examples:
using (var context = new UnicornsContext())
{
// Query for all unicorns with names starting with B
var unicorns = from u in context.Unicorns
where u.Name.StartsWith("B")
select u;
// Query for the unicorn named Binky
var binky = context.Unicorns
.Where(u => u.Name == "Binky")
.FirstOrDefault();
}
Note that DbSet and IDbSet always create queries against the database and will always involve a round trip to the database even if the entities returned already exist in the context.
Finding entities using primary keys
The Find method on DbSet uses the primary key value to attempt to find an entity tracked by the context. If the entity is not found in the context then a query will be sent to the database to find the entity there. Null is returned if the entity is not found in the context or in the database.
Find is different from using a query in two significant ways:
- A round-trip to the database will only be made if the entity with the given key is not found in the context.
- Find will return entities that are in the Added state. That is, Find will return entities that have been added to the context but have not yet been saved to the database.
Finding an entity by primary key
The following code shows some uses of Find:
using (var context = new UnicornsContext())
{
// Will hit the database
var unicorn = context.Unicorns.Find(3);
// Will return the same instance without hitting the database
var unicornAgain = context.Unicorns.Find(3);
context.Unicorns.Add(new Unicorn { Id = -1 });
// Will find the new unicorn even though it does not exist in the database
var newUnicorn = context.Unicorns.Find(-1);
// Will find a castle which has a string primary key
var castle = context.Castles.Find("The EF Castle");
}
Finding an entity by composite primary key
In the model presented in Part 1 of this series, the LadyInWaiting entity type has a composite primary key formed from the PrincessId and the CastleName properties—a princess can have one lady-in-waiting in each castle. The following code attempts to find a LadyInWaiting with PrincessId = 3 and CastleName = “The EF Castle”:
using (var context = new UnicornsContext())
{
var lady = context.LadiesInWaiting.Find(3, "The EF Castle");
}
Note that in the model the ColumnAttribute was used to specify an ordering for the two properties of the composite key. The call to Find must use this order when specifying the two values that form the key.
Summary
In this part of the series we showed how to find entities using LINQ queries and also how to use Find to find entities using their primary key values.
As always we would love to hear any feedback you have by commenting on this blog post.
For support please use the Entity Framework Forum.
Arthur Vickers
Developer
ADO.NET Entity Framework
Comments
Anonymous
February 28, 2011
Is it possible to get executed SQL in application? Does DbQuery have any equivalent to ObjectQuery.ToTraceString?Anonymous
March 02, 2011
@Ladislav Use DbQuery.ToString().Anonymous
May 19, 2011
I am not able to Find the entity using the Find method. Guid test = (Guid)Membership.GetUser(username).ProviderUserKey; userDetails = kestralDB.userDetails.Find(test); username => string username variable. I am getting the proper "test" Guid variable from the first statement. However when I am passing it in the second statement, I am getting null as the userDetails. userDetails table is existing in the database and I have used the DbContext to add elements to the userDetails class.Anonymous
June 13, 2011
Everything I've read about EF 4.1 suggests using something like new Unicorn { Id = -1 } is not good practice. It should be: context.Unicorns.Create(). I know this is a minor point, and not really critical to the current topic, but it would be nice if the ADO.NET developer's posts were a bit more consistent, to help users avoid these little gotchas.Anonymous
January 24, 2012
@Sumesh: The code you posted should work. I’m not sure why it’s not working for you without more details. @pk: Most of the time it is not necessary to use the Create method to create entities. If you are using change tracking proxies, then you may need to do this to ensure that your get a change tracking proxy, but none of these examples use change tracking proxies. When using lazy loading proxies it usually doesn’t matter that you don’t have a proxy for the new entity because you usually don’t expect lazy loading for this entity anyway, since it isn’t even in the database yet. Thanks, ArthurAnonymous
May 30, 2012
I'm using EF 4.3.1 and having difficulty getting your example code to work. Don't know if 4.3.1 is substantially different from 4.1 example or I'm doing something wrong. Also tried this in EF5.0 pre-release --no joy either. var unicorns = from u in context.Unicorns where u.Name.StartsWith("B") select u; produces error: MetadataException was unhandled At least one SSDL artifact is required for creating StoreItemCollection. Doesn't your "Code First" build the CSDL, SSDL, and MSL automagically as part of the assembly? If not, how, what, and where do I specify it? I'm not using SQLCE or SQL Express, but regular SQL Server. Shouldn't a Unicorns.MDF file be created somewhere with the Unicorns catalog added so SQL Server Management Studio sees it if it doesn't exist? Can you post a working solution? public class UnicornsContext : System.Data.Entity.DbContext { public UnicornsContext() : base("UnicornsEntities") { } My App.Config file: <?xml version="1.0" encoding="utf-8"?> <configuration> <configSections> <!-- For more information on Entity Framework configuration, visit go.microsoft.com/fwlink --> <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=4.3.1.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> </configSections> <connectionStrings> <add name="UnicornsEntities" connectionString="Metadata=res://*/;provider=System.Data.SqlClient;provider connection string="data source=jb-laptopjblaptop;initial catalog=Unicorns;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" /> </connectionStrings> <entityFramework> <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework"> <parameters> <parameter value="Data Source=(localdb)v11.0; Integrated Security=True; MultipleActiveResultSets=True" /> </parameters> </defaultConnectionFactory> </entityFramework> </configuration>Anonymous
May 31, 2012
@Jules.Bartow To use Code First you need to use a "normal" connection string rather than an EF connection string. This is because the EF connection string is only used to provide references to the XML containing the model which is not needed in Code First since the model is defined by the code. Try something like this: <add name="UnicornsEntities" connectionString="data source=jb-laptopjblaptop;initial catalog=Unicorns;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />Anonymous
June 18, 2012
The comment has been removedAnonymous
June 18, 2012
@Jules.Bartow Find doesn't currently support eager loading. It is something we have heard requests for and may add in the future. Find is mostly for looking up a single entity by primary key without hitting the database if that entity is already loaded into the context. This is an unambiguous operation. Once you start to extend this concept to query by things other than the primary key or to include more than one entity it starts to get a bit more difficult to define when to hit the database, which part of the query should/can be done locally, and how to deal with semantic differences between local and database queries. This is not to say we couldn't define something that would work and be useful, but it is non-trivial, and the benefits of doing this with Find over just using LINQ to Entities are not always obvious. So, for the moment, if you want more than just a single entity looked up by primary key then the way to do it is with LINQ.Anonymous
July 16, 2012
no explanation about how to use Any(), Select(), All() methods?Anonymous
July 16, 2012
@Thupten Find does not create a LINQ query and so does not support these methods. If you are writing a LINQ query (such as is shown in "Finding entities using a query") then they work in the normal way--for more details see the MSDN documentation for the methods or any of the many other resources that describe LINQ.Anonymous
July 29, 2012
Hi Arthur; Firstly, I like to thank you the way you had answered all the questions with useful and informative answers. My confusion with "Find" comes with the clause "Find will return entities that are in the Added state". Does this mean with "Find" I can only look for an entity by primary ID, ONLY while my DbContext is alive and I can ONLY see entities that have been added while this DbContext instance was created? Another words, if I create another instance of DbContext and look for the same Entity, I will NOT find it, because it's not hitting the database??? This is my confusion about "Not hitting the database". Thank you in advance. ..BenAnonymous
July 31, 2012
@Ben Hayat Find looks in your context first for an entity with the given key. If no entity is found in the context it then looks in the database. So if the entity is already being tracked by the context then it will be returned without hitting the database, but if it is not being tracked by the context and has been saved to the database then Find will hit the database and return the entity. This means that if you save an entity in one context then you can get it from the database with Find from a different context.Anonymous
June 26, 2013
how to find by other field name like by author_id, email, etc?Anonymous
June 27, 2013
@aditia - You need to use a query for this: var person = (from p in context.People where p.Email == "joe@example.com" select p).FirstOrDefault();