If you need to get a record from the database by its primary key, you can use both methods. Both methods will return an entity object if the record is present in the database; otherwise, they will return null .

What is their difference and when what method to use?

    1 answer 1

    To search and retrieve an entity object, you can use the methods:

    Find() , First() , FirstOrDefault() , Single() , SingleOrDefault() .

    Consider each:

    • The Find() method takes as a parameter the primary key of the record.

      Its peculiarity is that, unlike other methods, it first accesses memory and searches for a record among context objects tracked by EntityFramework, and only then (if it has not found anything) fulfills a query to the database. If there is an object in the context that is not yet stored in the database, the Find() method will still return it (with the Added status). If the record is not found neither there nor there, it returns null .

      Generated SQL query:

       SELECT TOP (2) [Extent1].[Id] AS [Id], [Extent1].[Title] AS [Title], FROM [dbo].[Topics] AS [Extent1] WHERE [Extent1].[Id] = @p0 

      It is worth paying attention that not one record gets into the sample, but two SELECT TOP (2) . This is used by internal EF mechanisms to verify the uniqueness of the record. If the result is more than one record with the same primary key, EF will throw an exception:

      System.InvalidOperationException: "The sequence contains more than one element"

    • The FirstOrDefault() method accepts a predicate as a parameter, which makes it possible to search not only for the primary key, but also for any condition that is composed.

      For example, find the record with Title == "test" :

       var topic = context.Topics.FirstOrDefault(topic => topic.Title == "test"); 

      FirstOrDefault() , unlike Find() performs a database query every time, regardless of whether the data is in context. If a record comes from the database that is different from the one that lies in the context, the EF will return the record from the context. If the record is not in the database, returns null , even if it is in context.

      Generated SQL query:

       SELECT TOP (1) [Extent1].[Id] AS [Id], [Extent1].[Title] AS [Title], FROM [dbo].[Topics] AS [Extent1] WHERE [Extent1].[Id] = @p__linq__0 

      It searches for only one SELECT TOP (1) record. If it turns out that there are several entries, it will return the first one.

    • The First() method is similar to FirstOrDefault() with one difference - if the record is not found, an exception will be thrown:

      System.InvalidOperationException: "The sequence contains no elements"

    • The SingleOrDefault() method is similar to FirstOrDefault() and returns an entity object, or null . However, the query generates a similar Find() method:

       SELECT TOP (2) [Extent1].[Id] AS [Id], [Extent1].[Title] AS [Title], FROM [dbo].[Topics] AS [Extent1] WHERE [Extent1].[Id] = @p__linq__0 

      And if more than one record is found, it throws an exception:

      System.InvalidOperationException: "The sequence contains more than one element"

    • The Single() method is similar to SingleOrDefault() and differs in that if an entry is not found, an exception will be thrown:

      System.InvalidOperationException: "The sequence contains no elements"


    Let's sum up:

    1. When to use Find() ?

      When you need to search by the primary key and you need to select all the entity data. Find() does not execute the query if the record is already loaded into the context and, as a result, will outperform all other methods in performance. However, if you need to select some specific fields (for example, only Id and Title ), you will have to use the other methods. The same applies to loading the dependent data (for example, via Include() ) - Find() will not do this.

    2. When to use other methods?

      If you need to select certain fields of an entity or need to also load dependent data. Which methods to use depends on individual requirements: if you need to check the existence of a record (without generating exceptions), *OrDefault() methods will *OrDefault() :

       var topic = context.Topics .Select(topic => new { topic.Id, topic.Title }) .FirstOrDefault(topic => topic.Id == 44); if (topic == null) { // ... } 

      If it is assumed that the context may contain local copies of the data, you can get them from there, without performing a database query. To do this, refer to the Local property of the DbSet object:

       Var topic = context.Topics.Local.FirstOrDefault(topic => topic.Id == topicId) ?? context.Topics.FirstOrDefault(topic => topic.Id == topicId); 

    Sources used:

    • EMENIP FirstOrDefault also can search by internal cache - Pavel Mayorov
    • @PavelMayorov rechecked, returns null even if the object is in the cache - tretetex
    • The Find() method takes as input a whole collection of primary keys. - user3172616