Difference between DbSet property and Set() function in EF Core?

c# entity-framework-core

Question

Given this kind of context:

public class FooContext : DbContext 
{
    public FooContext(DbContextOptions<FooContext> opts) : base(opts)
    { }

    public DbSet<Bar> Bars { get; set; }
}

I can get to a Bar in two ways:

fooContext.Bars.Add(new Bar()); // Approach 1

or

fooContext.Set<Bar>().Add(new Bar()); // Approach 2

What is the difference between the two approaches?

I've tried to answer my own question by:

But I could not find any good explanation about which of the two is used for which purpose. What is the difference? Or perhaps more importantly: where and how should I be able to find this in the docs?

1
5
11/25/2018 4:26:03 PM

Accepted Answer

They do exactly the same thing. The real question is when will you use one over the other.

You use DbSet when you know the type of entity you want to play with. You simple write the DbContext name then the entity type name and you can create, read, update or delete entries for this entity with the entity methods available. You know what you want and you know where to do it.

You use Set when you don't know the entity type you want to play with. Lets say, you wanted to build a class that does your repository functions for creating, reading, updating and deleting entries for an entity. You want this class to be reusable so that you can just pass a DbContext on it and it will use the same create, read, update and delete methods. You don't know for sure what DbContext it will be used on or what DbSet the DbContext will have. Here's when you use generics so that your class can be used by any DbContext for any DbSet.

Here's an example of a class you can use for creating any entity on any DbSet in any DbContext

public class Repository<TDbContext> where TDbContext : DbContext
{
    private TDbContext _context { get; }

    public Repository(TDbContext context)
    {
       _context = context;
    }

    public TEntity Create<TEntity>(TEntity entity) where TEntity : class
    {
        if(entity != null)
        {
            var dataSet = _context.Set<TEntity>();

            if(entity is IEnumerable)
            {
                dataSet.AddRange(entity);
            }
            else
            {
                dataSet.Add(entity);
            }

            _context.SaveChanges();


        }

        return entity;
    }
}

And this is how to use it.

var dbContext01 = new DbContext01();
var dbContext02 = new DbContext02();

var repository01 = new Repository<DbContext01>(dbContext01);
var repository02 = new Repository<DbContext02>(dbContext02);

repository01.Create(new EntityOnDbContext01 {
    Property01A = "String",
    Property01B = "String"
});

repository02.Create(new EntityOnDbContext02 {
    Property02A = 12345,
    Property02B = 12345
});

Here's a link if you want to know more about generics. Its super awesome.

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/

7
11/25/2018 5:29:10 PM

Popular Answer

Unfortunately currently you won't find explanation in the official documentation, mainly because all these are functionally equivalent.

First, the generic methods of DbConext like Add<TEntity>, Remove<TEntity>, Attach<TEntity> etc. a fully equivalent of the corresponding DbSet<TEntity> methods (actually currently they are the implementation of the later, i.e. DbSet methods simply call the corresponding DbContext generic method). Which one you use is just a matter of taste.

Second, DbSet<TEntity> property and Set<TEntity> method are functionally equivalent, but do have some non functional differences.

The DbSet properties are populated once at the context creation, while Set method always performs a lookup, so DbSet property access should be faster than Set method (although not significant).

The important difference is actually the EF Core Including & Excluding Types convention:

By convention, types that are exposed in DbSet properties on your context are included in your model. In addition, types that are mentioned in the OnModelCreating method are also included.

So while you can keep your DbContext without exposed DbSet properties and work just with Set method, if you do so you have to tell explicitly EF Core which are your entity types by adding in OnModelCreating a call to modelBuilder.Entity<TEntity>(); for each entity type (this is what the documentation does mean by types that are mentioned in the OnModelCreating method).



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow