2016-04-14 41 views
1

我使用这个框架:URFCaliburn Micro来创建业务WPF应用程序。URF与WPF MVVM卡利微

这是CM引导程序的代码:

public class Bootstrapper : BootstrapperBase 
{ 
    private SimpleContainer container; 

    public Bootstrapper() 
    { 
     Initialize(); 
    } 

    protected override void Configure() 
    { 
     container = new SimpleContainer(); 

     container.Singleton<IWindowManager, WindowManager>(); 
     container.Singleton<IEventAggregator, EventAggregator>(); 

     container.PerRequest<IShell, ShellViewModel>(); 
     container.AllTypesOf<ITabItem>(Assembly.GetExecutingAssembly()); 

     container.PerRequest<IDataContextAsync, AuraContext>(); 
     container.PerRequest<IUnitOfWorkAsync, UnitOfWork>(); 
     container.PerRequest<IRepositoryAsync<Audit>, Repository<Audit>>(); 
     container.PerRequest<IAuditService, AuditService>(); 
    } 

    protected override object GetInstance(Type service, string key) 
    { 
     var instance = container.GetInstance(service, key); 
     if (instance != null) 
      return instance; 

     throw new InvalidOperationException(String.Format("Could not locate any instances of type {0}", service.Name)); 
    } 

    protected override IEnumerable<object> GetAllInstances(Type serviceType) 
    { 
     return container.GetAllInstances(serviceType); 
    } 

    protected override void BuildUp(object instance) 
    { 
     container.BuildUp(instance); 
    } 

    protected override void OnStartup(object sender, StartupEventArgs e) 
    { 
     DisplayRootViewFor<IShell>(); 
    } 
} 

的ShellViewModel.cs代码:

public class ShellViewModel: Conductor<ITabItem>.Collection.OneActive, IShell 
{ 
    private readonly IWindowManager _windowManager; 

    [ImportingConstructor] 
    public ShellViewModel(IWindowManager windowManager, IEnumerable<ITabItem> tabItems) 
    { 
     DisplayName = "Aura"; 

     _windowManager = windowManager; 

     Items.AddRange(tabItems.Where(t => t.IsEnabled).OrderBy(t => t.DisplayOrder)); 
    } 
} 

的ShellView.xaml标记:

<UserControl x:Class="Aura.ShellView" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:local="clr-namespace:Aura"    
      mc:Ignorable="d"  
      d:DesignHeight="300" d:DesignWidth="600" MinWidth="800" MinHeight="600"> 

    <TabControl x:Name="Items" Margin="3"> 

</UserControl> 

这是一些储存库:

public static class AuditRepository 
{ 
    public static async Task<Audit> GetCurrentAudit(this IRepositoryAsync<Audit> repository) 
    { 
     var audits = await repository 
       .Query(a => a.BeginDate.Year == DateTime.Now.Year) 
       .Include() 
       .SelectAsync(); ; 

     return audits.FirstOrDefault(); 
    } 

    public static IEnumerable<Reminder> GetRemindersForAudit(this IRepositoryAsync<Audit> repository, int auditId) 
    { 
     var audits = repository.GetRepository<Audit>().Queryable(); 
     var phases = repository.GetRepository<Phase>().Queryable(); 
     var reminders = repository.GetRepository<Reminder>().Queryable(); 

     var query = from audit in audits 
        where audit.Id == auditId 
         join phase in phases on audit.Id equals phase.AuditId 
         join reminder in reminders on phase.Id equals reminder.PhaseId 
        select reminder; 

     return query.AsEnumerable(); 
    } 
} 

及其服务:

public interface IAuditService: IService<Audit> 
{ 
    Task<Audit> GetCurrentAudit(); 
} 

public class AuditService: Service<Audit>, IAuditService 
{ 
    private readonly IRepositoryAsync<Audit> _repository; 

    public AuditService(IRepositoryAsync<Audit> repository) 
     :base(repository) 
    { 
     _repository = repository; 
    } 

    public async Task<Audit> GetCurrentAudit() 
    { 
     return await _repository.GetCurrentAudit(); 
    } 

    public override void Delete(Audit entity) 
    { 
     // business logic here 
     base.Delete(entity); 
    } 

    public override void Update(Audit entity) 
    { 
     // business logic here 
     base.Update(entity); 
    } 

    public override void Insert(Audit entity) 
    { 
     // business logic here 
     base.Insert(entity); 
    } 
} 

这是我的ViewModels构造:

[ImportingConstructor] 
public AdminViewModel(
    IWindowManager windowManager, 
    IEventAggregator eventAggregator, 
    IUnitOfWorkAsync unitOfWorkAsync, 
    IAuditService auditService) 
{ 
    _windowManager = windowManager; 
    _eventAggregator = eventAggregator; 
    _unitOfWorkAsync = unitOfWorkAsync; 
    _auditService = auditService 
} 

并在视图模型多数民众赞成让我问题的执行情况:

try 
{ 

    //var audits = await _unitOfWorkAsync.RepositoryAsync<Audit>().Query().SelectAsync(); 

    //Audits = new ObservableCollection<Audit>(audits); 
    SelectedAudit = await _auditService.GetCurrentAudit(); 
    //AuditHistoryHeader = String.Format(Constants.ADMINVIEW_AUDITHISTORYHEADER, Audits.Count); 

    SelectedAudit.ObjectState = ObjectState.Deleted; 
    _auditService.Delete(SelectedAudit); 
    _unitOfWorkAsync.SaveChanges(); 

    var audit = _unitOfWorkAsync.Repository<Audit>().Query().Select().FirstOrDefault(); 

    _unitOfWorkAsync.Repository<Audit>().Delete(audit); 
    _unitOfWorkAsync.SaveChanges(); 


} 
catch (Exception ex) 
{ 
    Console.WriteLine(ex.Message); 
} 

什么我不知道在URFUnitOfWork.cs文件:

public IRepository<TEntity> Repository<TEntity>() where TEntity : Entity, IEntity 
{ 
    try 
    { 
     if (ServiceLocator.IsLocationProviderSet) 
     //if (ServiceLocator.Current != null) 
     //{ 
      return ServiceLocator.Current.GetInstance<IRepository<TEntity>>(); 
     //} 
    } 
    catch (Exception) 
    { 

    } 

    return RepositoryAsync<TEntity>(); 
    //return IoC.Get<IRepositoryAsync<TEntity>>(); 
} 

的问题是,坚持CRUD操作数据库的唯一方法是与_unitOfWorkAsync.Repository()对象,而不是使用服务。 这并不失败,但在数据库中没有变化..我有点不确定在URF使用的ServiceLocatorSimpleContainerCaliburn Micro以及它们如何(应)一起工作。我也不能确定该寿命容器Bootstrapper.cs文件对象。

我刚开始了解DI模式,但我认为这是什么给我,我遇到的问题..

如果有人已经做过类似的或看到的问题是什么,请让我知道。如果你想看到更多的代码,请在下面评论。

编辑:

我试过以下,但数据不会被删除..

try 
{ 
    SelectedAudit = await _auditService.GetCurrentAudit(); 
    SelectedAudit.ObjectState = ObjectState.Deleted; 

    _unitOfWorkAsync.SaveChanges(); 
} 
catch (Exception ex) 
{ 
    Console.WriteLine(ex.Message); 
} 

如果我步入UnitOfWork.cs SaveChanges并观看IDataContextAsync _dataContext审计dbSet审计有ObjectState Unchanged。因此,删除的审计不是该情况的一部分?!

回答

1

我不会说你的DI设置,因为我从来没有使用SimpleContainer(我使用URF与Autofac)。你不确定URF中的代码是否正确。与Autofac和Ninject非常相称,所以我猜SimpleContainer会相似。但我看到的一个问题是在以下几行代码中:

SelectedAudit = await _auditService.GetCurrentAudit(); 
//AuditHistoryHeader = String.Format(Constants.ADMINVIEW_AUDITHISTORYHEADER, Audits.Count); 

SelectedAudit.ObjectState = ObjectState.Deleted; 
_auditService.Delete(SelectedAudit); // <-- This is a problem 
_unitOfWorkAsync.SaveChanges(); 

首先,您会看到SelectedAudit。 SelectedAudit现在正在被实体框架跟踪。然后,您将SelectedAudit的状态设置为删除。到现在为止还挺好。你现在要做的就是调用Savechanges。 SelectedAudit已经附加到实体框架上下文中,并将其标记为已删除状态,足以让实体框架知道将其删除。从您的服务调用删除将尝试再次将SelectedAudit附加到上下文。这会引发异常(很可能)或导致不希望的行为。如果你删除线

_auditService.Delete(SelectedAudit); 

它应该工作。请注意,对于实体更新,这是相同的。获取实体,对其进行更改,然后调用SaveChanges而不调用您的服务更新方法。

如果您没有在同一上下文中首次获取实体,则只应使用更新/删除方法。

至于生命周期管理,默认URF使用PerRequest来处理IDataContextAsync,IUnitOfWorkAsync和INorthwindStoredProcedures。其余全部使用TransientLifetime。坚持并改变,如果你需要。

额外信息 我修改了我的服务来接受viewmodels而不是实体。这是我使用的服务。我更喜欢这个,因为它在DAL和Web层之间保持了更好的分离(IMO)。

public interface IService<TModel> 
{ 
    TModel Find(params object[] keyValues); 
    Task<TModel> Insert(TModel model); 
    IEnumerable<TModel> InsertRange(IEnumerable<TModel> models); 
    Task<TModel> Update(TModel model); 
    void Delete(object id); 
    void Delete(TModel model); 
    Task<TModel> FindAsync(params object[] keyValues); 
    Task<TModel> FindAsync(CancellationToken cancellationToken, params object[] keyValues); 
    Task<bool> DeleteAsync(params object[] keyValues); 
    Task<bool> DeleteAsync(CancellationToken cancellationToken, params object[] keyValues); 
} 

public abstract class Service<TModel, TEntity> : IService<TModel> where TEntity : class, IObjectState 
{ 
    #region Private Fields 

    private readonly IRepositoryAsync<TEntity> _repository; 
    private readonly IUnitOfWorkAsync _unitOfWork; 
    private readonly IMapper _mapper; 

    #endregion Private Fields 

    #region Constructor 

    protected Service(IRepositoryAsync<TEntity> repository, IUnitOfWorkAsync unitOfWork, IMapper mapper) 
    { 
     _repository = repository; 
     _unitOfWork = unitOfWork; 
     _mapper = mapper; 
    } 

    #endregion Constructor 

    public void Delete(TModel model) 
    { 
     _unitOfWork.RepositoryAsync<TEntity>().Delete(_mapper.Map<TEntity>(model)); 
     _unitOfWork.SaveChanges(); 
    } 

    public void Delete(object id) 
    { 
     _unitOfWork.RepositoryAsync<TEntity>().Delete(id); 
     _unitOfWork.SaveChanges(); 
    } 

    public async Task<bool> DeleteAsync(params object[] keyValues) 
    { 
     return await DeleteAsync(CancellationToken.None, keyValues); 
    } 

    public async Task<bool> DeleteAsync(CancellationToken cancellationToken, params object[] keyValues) 
    { 
     var result = await _unitOfWork.RepositoryAsync<TEntity>().DeleteAsync(cancellationToken, keyValues); 
     _unitOfWork.SaveChanges(); 
     return result; 
    } 

    public TModel Find(params object[] keyValues) 
    { 
     return _mapper.Map<TModel>(_repository.Find(keyValues)); 
    } 

    public async Task<TModel> FindAsync(params object[] keyValues) 
    { 
     var entity = await _repository.FindAsync(keyValues); 
     return _mapper.Map<TModel>(entity); 
    } 

    public async Task<TModel> FindAsync(CancellationToken cancellationToken, params object[] keyValues) 
    { 
     var entity = await _repository.FindAsync(cancellationToken, keyValues); 
     return _mapper.Map<TModel>(entity); 
    } 

    public async Task<TModel> Insert(TModel model) 
    { 
     var entity = _unitOfWork.RepositoryAsync<TEntity>().Insert(_mapper.Map<TEntity>(model)); 
     await _unitOfWork.SaveChangesAsync(); 
     return _mapper.Map<TModel>(entity); 
    } 

    public IEnumerable<TModel> InsertRange(IEnumerable<TModel> models) 
    { 
     var entities = _unitOfWork.RepositoryAsync<TEntity>().InsertRange(_mapper.Map<IEnumerable<TEntity>>(models)); 
     _unitOfWork.SaveChanges(); 
     return _mapper.Map<IEnumerable<TModel>>(entities); 
    } 

    public async Task<TModel> Update(TModel model) 
    { 
     var entity = _unitOfWork.RepositoryAsync<TEntity>().Update(_mapper.Map<TEntity>(model)); 
     await _unitOfWork.SaveChangesAsync(); 
     return _mapper.Map<TModel>(entity); 
    } 

    public async Task<TModel> UpdateFieldsOnly(TModel model, params string[] fields) 
    { 
     var entity = _unitOfWork.RepositoryAsync<TEntity>().UpdateFieldsOnly(_mapper.Map<TEntity>(model), fields); 
     await _unitOfWork.SaveChangesAsync(); 
     return _mapper.Map<TModel>(entity); 
    } 
} 
+0

嗨garethb,谢谢你的回答。我会在大约1小时的工作时间试试这个。但是,如果我无法通过现有实体,我对服务的更新方法有点不确定。你如何去做? – grmbl

+0

我通常会将viewmodel传递给我的服务。从我的服务中,我得到实体并将视图模型映射到实体,就像我在服务中那样。 var entity = _repository.Find(viewmodel.Id); entity.FirstName = viewmodel.FirstName; entity.ObjectState = ObjectState.Modified; _unitOfWork.SaveChanges(); – garethb

+0

查看我的修改服务的更新答案。注意我使用Automapper来映射我的模型和实体,但也可以手动映射。 – garethb