Разница между свойством DbSet <T>и функцией Set <T>() в EF Core? - PullRequest
0 голосов
/ 25 ноября 2018

Учитывая этот вид контекста:

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

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

Я могу добраться до Bar двумя способами:

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

или

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

ЧтоРазница между этими двумя подходами?

Я пытался ответить на свой вопрос следующим образом:

Но яне смог найти хорошего объяснения о том, какой из двух используется для какой цели.В чем разница?Или, возможно, еще важнее: где и как мне найти это в документации?

Ответы [ 3 ]

0 голосов
/ 25 ноября 2018

Они одинаковы и фактически возвращают один и тот же экземпляр DbSet.

var options = //...;

using (var ctx = new FooContext(options))
{
    // true
    bool isSame = ReferenceEquals(ctx.Bars, ctx.Set<Bar>());
}

Один из случаев, когда вы не включаете свойство DbSet в свой DbContext, - это когда вы хотите скрыть сущностьтипа от потребителя.(например, объект, который действует как таблица соединения для отношения «многие ко многим» ).Затем вы можете пометить объект как internal class, чтобы потребители также не могли получить к нему доступ, используя Set<>.

Кроме того, если вы не предоставляете свойство DbSet, вам необходимо явно настроитьили вы получите следующее исключение:

//throws System.InvalidOperationException: 'The entity type 'Foo' was not found. Ensure that the entity type has been added to the model.'
ctx.Set<Foo>().Add(new Foo());    
0 голосов
/ 25 ноября 2018

К сожалению, в настоящее время вы не найдете объяснения в официальной документации, в основном потому, что все они функционально эквивалентны.

Во-первых, универсальные методы DbConext подобно Add<TEntity>, Remove<TEntity>, Attach<TEntity> и т. д., полностью эквивалентным соответствующим DbSet<TEntity> методам (на самом деле в настоящее время они являются реализацией более поздних, т.е. DbSet методы просто вызывают соответствующий обобщенный метод DbContext).).Какой из них вы используете - дело вкуса.

Во-вторых, свойство DbSet<TEntity> и метод Set<TEntity> функционально эквивалентны, но имеет некоторые нефункциональные различия.

Свойства DbSet заполняются один раз при создании контекста, в то время как метод Set всегда выполняет поиск, поэтому доступ к свойству DbSet должен быть быстрее, чем метод Set (хотя и незначительный).

Важным отличием является EF Core Включая и исключая типы соглашение:

По соглашению типы, представленные в свойствах DbSet вашего контекста,включены в вашу модель.Кроме того, включены типы, упомянутые в методе OnModelCreating.

Таким образом, пока вы можете сохранять свои DbContext без открытых DbSet свойств и работать только с методом Set,если вы сделаете это, вы должны явно указать EF Core, какие у вас типы сущностей, добавив в OnModelCreating вызов modelBuilder.Entity<TEntity>(); для каждого типа сущности (это то, что документация подразумевает под типами, упомянутыми вOnModelCreating метод ).

0 голосов
/ 25 ноября 2018

Они делают то же самое.Реальный вопрос в том, когда вы будете использовать один над другим.

Вы используете DbSet, когда знаете тип сущности, с которой хотите играть.Вы просто пишете имя DbContext, а затем имя типа объекта, и вы можете создавать, читать, обновлять или удалять записи для этого объекта с помощью доступных методов объекта.Вы знаете, чего хотите, и знаете, где это сделать.

Вы используете Set, когда не знаете тип сущности, с которой хотите играть.Допустим, вы хотели создать класс, который выполняет функции вашего хранилища для создания, чтения, обновления и удаления записей для сущности.Вы хотите, чтобы этот класс можно было повторно использовать, чтобы вы могли просто передать ему DbContext, и он будет использовать те же методы создания, чтения, обновления и удаления.Вы не знаете наверняка, на каком DbContext он будет использоваться или какой DbSet будет у DbContext.Вот когда вы используете дженерики, чтобы ваш класс мог использоваться любым DbContext для любого DbSet.

Вот пример класса, который вы можете использовать для создания любого объекта в любом DbSet в любом 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;
    }
}

А вот как это использовать.

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
});

Вот ссылка, если вы хотите узнать больше о дженериках.Это супер круто.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...