Использование DI в AspNET Core

Эта проблема имеет две типичные причины:

  • Статические поля, используемые объектами, которые вы сохранили в списке
  • Случайно добавив тот же объект в список

Статические поля

Если объекты в вашем списке хранят данные в статических полях, каждый объект в вашем списке будет казаться одним и тем же, поскольку они удерживают одинаковые значения. Рассмотрим следующий класс:

public class Foo {
  private static int value; 
  //      ^^^^^^------------ - Here's the problem!

  public Foo(int value) {
    this.value = value;
  }

  public int getValue() {
    return value;
  }
}

В этом примере есть только один int value, который разделяется между всеми экземплярами Foo, поскольку он объявлен static. (См. учебник «Знакомство с членами класса» .)

Если вы добавите несколько объектов Foo в список, используя приведенный ниже код, каждый экземпляр вернет 3 из вызова to getValue():

for (int i = 0; i < 4; i++) {      
  list.add(new Foo(i));
}

Решение прост - не используйте ключевые слова static для полей вашего класса, если вы действительно не хотите, чтобы значения были разделены между каждым экземпляром этого класса.

Добавление одного и того же объекта

Если вы добавите временную переменную в список, вы должны создать новый экземпляр каждый раз, когда вы выполняете цикл. Рассмотрим следующий ошибочный фрагмент кода:

List list = new ArrayList();    
Foo tmp = new Foo();

for (int i = 0; i < 3; i++) {
  tmp.setValue(i);
  list.add(tmp);
}

Здесь объект tmp был создан вне цикла. В результате один экземпляр объекта добавляется в список три раза. Экземпляр будет содержать значение 2, потому что это значение было передано во время последнего вызова setValue().

Чтобы исправить это, просто переместите конструкцию объекта внутри цикла:

List list = new ArrayList();        

for (int i = 0; i < 3; i++) {
  Foo tmp = new Foo(); // <-- fresh instance!
  tmp.setValue(i);
  list.add(tmp);
}

1
задан Riddari 16 January 2019 в 22:21
поделиться

2 ответа

Вы вообще не используете new NavigationContext(...), вы полностью упускаете точку внедрения зависимости, если делаете это. Вместо этого вы должны внедрить контекст в класс, который в этом нуждается. Например, если вам нужно это прямо в вашем контроллере, это будет выглядеть примерно так:

public class FunkyController : Controller
{
    private readonly NavigationContext _nagivationContext;

    public FunkyController(NagivationContext nagivationContext)
    {
        //Context is injected into the constructor of the controller
        _nagivationContext = nagivationContext;
    }

    public int Add(TEntity item)
    {
        _nagivationContext.Set<TEntity>().Add(item);
        _nagivationContext.SaveChanges();
        return item.Id;
    }
}
0
ответ дан DavidG 16 January 2019 в 22:21
поделиться

Это не так, как вы делаете DI (Dependency Injection). Всякий раз, когда вы видите ключевое слово new для службы, вы должны знать, что это неправильно.

Во-первых, вам не нужно ничего передавать в DbContext, этого переопределения OnConfiguring не должно быть, поскольку вы его не используете. Этот вызов заботится об этой конфигурации:

services.AddDbContext<NavigationContext>(options => options.UseSqlServer(Configuration.GetConnectionString("NavigationLoggingDatabase")));

Во-вторых, вы не используете using с внедренными зависимостями, поэтому:

public int Add(TEntity item)
{
    _context.Set<TEntity>().Add(item);
    _context.SaveChanges();
    return item.Id;
}

И, чтобы это работало: [ 1110]

public class SomeController : Controller
{
    private readonly NavigationContext _context;

    public SomeController(NagivationContext context)
    {
        _context = context;
    }
}

И, как последний совет, вы должны действительно, действительно, максимально использовать асинхронные версии методов Entity Framework Core:

public async Task<int> Add(TEntity item)
{
    _context.Set<TEntity>().Add(item);
    await _context.SaveChangesAsync();
    return item.Id;
}
0
ответ дан Camilo Terevinto 16 January 2019 в 22:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: