Я использую эту структуру: URF и Caliburn Micro для создания бизнес-приложения WPF.URF с WPF MVVM Caliburn Micro
Это код 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>
Это некоторые Repository :
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
}
И реализация в этой ViewModel, который дает мне вопросы:
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(), а не с помощью службы. Это не подводит, но никаких изменений в БД. Я немного не уверен в том, что ServiceLocator
используется в URF и SimpleContainer
от Caliburn Micro и как они (должны) работать вместе. Я также не уверен в объектах контейнеров LifeTime в файле Bootstrapper.cs
.
Я только начинаю понимать картину DI, но я думаю, что это то, что дает мне меня вопрос ..
Если кто-то уже сделал что-то вроде этого или видит, что проблема есть, пожалуйста, дай мне знать. Если вам нравится больше кода, прокомментируйте это ниже.
EDIT:
Я попытался следующие, но данные не удаляются ..
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
. Итак, удаленный аудит не является частью этого контекста ?!
Привет, garethb, спасибо за ваш ответ. Я попробую это, когда я заработаю около часа. Но я немного не уверен в методе обновления службы, если я не могу передать существующий объект. Как вы это делаете? – grmbl
Я обычно передаю viewmodel к моей службе. Из моей службы я получаю объект и сопоставляю viewmodel с сущностью, что-то вроде этого в моем сервисе. var entity = _repository.Find (viewmodel.Id); entity.FirstName = viewmodel.FirstName; entity.ObjectState = ObjectState.Modified; _unitOfWork.SaveChanges(); – garethb
См. Обновленный ответ для моей измененной службы. Примечание. Я использую Automapper для сопоставления между моими моделями и сущностями, но вы также можете отображать их вручную. – garethb