2016-06-21 14 views
1

Я написал приложение WPF, но у меня возникла проблема с обновлением данных, которые извлекаются из базы данных SQL Server.Обновление данных в EntityFramework

Я использую StructureMap для ввода зависимостей, а также для управления жизненным циклом DBContext. Это моя конфигурация StructureMap:

ObjectFactory.Container.Configure(cfg => 
{ 
    cfg.For<IUnitOfWork>() 
     .LifecycleIs(new ThreadLocalStorageLifecycle()) 
     .Use<DBContext>(); 
}); 

Но когда я редактирую запись из другого экземпляра приложения или из SQL Server непосредственно, клиент который принес запись до того, не может обновить себя и просто показать немодифицированную данные.

Я использовал .LifecycleIs (новый ThreadLocalStorageLifecycle()) иметь различный контекст в каждом потоке, чтобы очистить кэш EntityFramework, но он не работает.

Это мой Класс обслуживания:

public class DraftService : IDraftService 
{ 
    IUnitOfWork _uow; 
    IDbSet<Models.Draft> _draft; 

    public DraftService(IUnitOfWork uow) 
    { 
     _uow = uow; 
     _draft = _uow.Set<Models.Draft>(); 
    } 

    public Models.Draft GetByID(long id) 
    { 
     return _draft.Find(id); 
    } 
} 

и я использую службу следующим образом:

public class Draft 
{ 
    private IUnitOfWork _uow; 
    private IDraftService _draftService; 

    public Draft(IUnitOfWork uow, IDraftService draftService) 
    { 
     _uow = uow; 
     _draftService = draftService; 
    } 

    public async Task<Models.Draft> GetByID(long id) 
    { 
     return await Task.Run(() => _draftService.GetByID(id)); 
    } 
} 

Что не так? Почему он не обновляет данные?

Заранее спасибо.

+0

Вы можете обернуть единицу работы на заводе и использовать ее в использовании (var uow = uowfactory.instance()) {// делаем что-то здесь // сохраняем в конце, чтобы сохранить данные.} Таким образом, вы не будет проблемы с кешем. или ошибки, которые могут возникнуть в результате использования одного и того же контекста для всей логики приложения. – Rugdr

+0

Вы правы Rugdr. Проблема в том, как избавиться от контекста? Не следует ".LifecycleIs (новый ThreadLocalStorageLifecycle()) работает и обновляет контекст для каждого потока? –

+0

Зависит от перезапуска приложения или нет. Думаю, в этом случае вам не следует использовать «AlwaysUnique» как время жизни. Таким образом, вам просто нужно вызовите Container.GetInstance (), чтобы получить новый/не кэшированный, уникальный контекст в базе данных. Должен также работать и поток. (но вам нужно будет получить новый экземпляр вашей службы каждый раз, когда вы хотите его обновить) – Rugdr

ответ

1

Я думаю, что StructureMap ISN» Ваша проблема, у вас есть проблема в отслеживании Entites. Дайте взглянуть на эту статью: http://www.entityframeworktutorial.net/change-tracking-in-entity-framework.aspx

Это может быть решена с помощью этого кода:

Models.Draft query = _draft.AsNoTracking().FirstOrDefault(r=>r.ID == id); 

Я надеюсь, что это помогает.

Отслеживание изменений в инфраструктуре Entity В этом разделе показано, как сущность Framework отслеживает изменения объектов.

1

Редактировать: После мгновения ясности вот что происходит.

заменить: return _draft.Find(id); // Find use the Cache if it can. By: return _draft.SingleOrDefault(x => x.id == id) // SingleOrDefault should Fetch from the database each time.


Мой комментарий не достаточно ясно, давайте взглянем на это:

public class DraftService : IDraftService 
{ 
IUnitOfWork _uow; <-- if this is disposed and _draft is accessed you'll get an error. 
IDbSet<Models.Draft> _draft; <-- might be cached. 

public DraftService(IUnitOfWork uow) 
{ 
    _uow = uow; <--- this context is always the same 
    _draft = _uow.Set<Models.Draft>(); 
} 

public Models.Draft GetByID(long id) 
{ 
    return _draft.Find(id); <---- this will always use the cached context. 
} 
} 

, если вы сделаете это выглядеть вместо этого. вы получите гораздо меньше проблем.

public class DraftService : IDraftService 
{ 
Container _ctn; 

public DraftService(Container ctn) 
{ 
    _ctn= ctn; 
} 

public Models.Draft GetByID(long id) 
{ 
    using(var uow = _ctn.Resolve<IUnitOfWork>()){ // new fresh context. don't forget the AlwaysUnique. 
    return uow.Set<Draft>().Find(id); // should return the newer revision. 
}} 
} 

, если вы не хотите, чтобы PASSE контейнер:

public class DraftService : IDraftService 
{ 
IUnitOfWorkResolver _rslv; 

public DraftService(IUnitOfWorkResolver rslv) 
{ 
    _rslv= rslv; 
} 

public Models.Draft GetByID(long id) 
{ 
    using(var uow = rslv.GetContext()){ // new fresh context. don't forget the AlwaysUnique. 
    return uow.Set<Draft>().Find(id); // should return the newer revision. 
}} 
} 


public class UnitOfWorkResolver{ 
    public IUnitOfWork GetContext(){ 
    return new DBContext(); //or whatever you want you could use Container.Resolve<IUnitOFWork>() instead. 
    } 
} 

я не ставил IUnitOfWorkResolver, но вы получите идею ...

+0

Это работает, но это решение не обрабатывает неявные транзакции, не так ли? –

+0

Вам не нужно обладать транзакцией в операторе using или управлять областью контекста самостоятельно и передавать объект uow методу, который будет использовать его , как параметр. Но так как у вас есть DraftService, я бы ожидал чего-то вроде: DraftService.Update (draft draftToUpdate), поэтому транзакция должна быть привязана только к методу обновления. – Rugdr

+0

Я не хочу использовать оператор using или явную транзакцию, так как мне нужно обрабатывать несколько служб в одной неявной транзакции. Представьте, что у меня есть DraftController, в этом контроллере мне нужно добавить экземпляр Draft и его State в базу данных в одной партии. Благодаря UnitOfWork он легко обрабатывался без какой-либо явной транзакции. Я использовал этот сценарий в веб-приложении, и он отлично работает, но в WPF это невозможно, потому что я не могу использовать «HybridHttpOrThreadLocalScoped()». Я думаю, что проблема с кэшем также выпущена для этой проблемы. Я прав? –