Подтвердить что ты не робот

В чем разница между DbSet <> и виртуальным DbSet <>?

В Entity Framework Code Сначала, когда я объявляю объекты, я должен использовать для этого свойства DbSet < > . Например:

public DbSet<Product> Products { get; set; }
public DbSet<Customer> Customers { get; set; }

Недавно я встретил DbSet < > объявленный как виртуальный.

public virtual DbSet<Product> Products { get; set; }
public virtual DbSet<Customer> Customers { get; set; }

В чем разница? Какие функции EF включены?

4b9b3361

Ответ 1

public class AppContext : DbContext
{
    public AppContext()
    {
        Configuration.LazyLoadingEnabled = true;
    }

    public virtual DbSet<AccountType> AccountTypes { get; set; }
}

public class AccountType
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<AccountCode> AccountCodes { get; set; }
}

public class AccountCode
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public Guid AccountTypeId { get; set; }
    public virtual AccountType AccountType { get; set; }
}

Виртуальное ключевое слово в свойствах навигации используется для включения ленивого механизма загрузки, но свойство LazyLoadingEnabled конфигурации должно быть включено.

Виртуальное ключевое слово в свойстве AccountType:: AccountCodes будет загружать все коды учетной записи в тот момент, когда есть программный доступ к этому свойству, в то время как контекст db все еще жив.

using (var context = new AppContext())
{
    var accountType = context.AccountTypes.FirstOrDefault();
    var accountCodes = accountType.AccountCodes;
}

В то время как ключевое слово virtual на производном классе DbContext (виртуальный DbSet < > ) используется для целей тестирования (издеваясь над свойством DbSet), виртуальное ключевое слово в этом случае не связано с ленивой загрузкой.

===== update =====

Обычно мы проводим тестирование против службы/логики, например, у нас есть другой уровень для службы типа учетной записи, как показано ниже. И служба принимает экземпляр контекста db, используя какую-либо инъекцию зависимостей через конструктор.

public class AccountTypeService
{
    public AppContext _context;

    public AccountTypeService(AppContext context)
    {
        _context = context;
    }

    public AccountType AddAccountType(string name)
    {
        var accountType = new AccountType { Id = Guid.NewGuid(), Name = name };
        _context.AccountTypes.Add(accountType);
        _context.SaveChanges();
        return accountType;
    }
}

И теперь нам нужно проверить службу типа учетной записи, в этом случае я использовал mstest и automoq для создания класса mock.

[TestClass]
public class AccountTypeServiceTest
{
    [TestMethod]
    public void AddAccountType_NormalTest()
    {
        // Arranges.
        var accountTypes = new List<AccountType>();
        var accountTypeSetMock = new Mock<DbSet<AccountType>>();
        accountTypeSetMock.Setup(m => m.Add(It.IsAny<AccountType>())).Callback<AccountType>(accountType => accountTypes.Add(accountType));

        var appContextMock = new Mock<AppContext>();
        appContextMock.Setup(m => m.AccountTypes).Returns(accountTypeSetMock.Object);
        var target = new AccountTypeService(appContextMock.Object);

        // Acts.
        var newAccountType = target.AddAccountType("test");

        // Asserts.
        accountTypeSetMock.Verify(m => m.Add(It.IsAny<AccountType>()), Times.Once());
        appContextMock.Verify(m => m.SaveChanges(), Times.Once());
        Assert.AreEqual(1, accountTypes.Count);
        Assert.IsNotNull(newAccountType);
        Assert.AreNotEqual(Guid.Empty, newAccountType.Id);
        Assert.AreEqual("test", newAccountType.Name);
    }
}

Ответ 2

Обратите внимание, что в EF Core (в настоящее время 1.0 и 2.0) по-прежнему не поддерживается схема LazyLoading, поэтому использование с "виртуальным" или без него не отличается.

FYI. Подкатегория, создающая ключевое слово "virtual" , может поддерживать технику LazyLoading в будущей версии EF Core!

(AFAIK в EF2.1 команда разработчиков может добавить поддержку LazyLoading)