URF与WPF MVVM卡利微
我使用这个框架:URF和Caliburn 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使用的ServiceLocator
和SimpleContainer
从Caliburn 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
。因此,删除的审计不是该情况的一部分?!
我不会说你的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);
}
}
嗨garethb,谢谢你的回答。我会在大约1小时的工作时间试试这个。但是,如果我无法通过现有实体,我对服务的更新方法有点不确定。你如何去做? – grmbl
我通常会将viewmodel传递给我的服务。从我的服务中,我得到实体并将视图模型映射到实体,就像我在服务中那样。 var entity = _repository.Find(viewmodel.Id); entity.FirstName = viewmodel.FirstName; entity.ObjectState = ObjectState.Modified; _unitOfWork.SaveChanges(); – garethb
查看我的修改服务的更新答案。注意我使用Automapper来映射我的模型和实体,但也可以手动映射。 – garethb