У меня есть решение, которое использует веб-формы для внешнего интерфейса и mvc для консоли администратора.
Оба интерфейса используют сервисный уровень через Ninject, и у меня возникают проблемы при разработке тонкой, но довольно важной проблемы.
Предположим, у меня есть CourseService, который возвращает список курсов, основанный на строковом поисковом термине - служба возвращает результаты поиска, но мне также нужно записать выполненный поиск и количество курсов, соответствующих этому термину, для управления. информационные цели.
Я начал с идеи, что единица работы будет зафиксирована пользовательским интерфейсом в конце запроса в методе страницы, таком как событие нажатия кнопки. То же самое относится к контроллеру.
Проблема здесь в том, что я полагаюсь на то, что разработчик пользовательского интерфейса вызовет Commit () для единицы работы, чтобы поиск был зарегистрирован. Разработчик пользовательского интерфейса мог бы успешно продолжить работу без вызова commit, и результаты будут возвращены - но поиск не будет зарегистрирован. Это приводит меня к решению позволить сервисному уровню контролировать объем единицы работы. Ninject автоматически передаст единицу работы как уровню обслуживания, так и реализации репозитория, и это будет фактически тот же самый экземпляр, как я сказал ninject, чтобы создать его для каждой области запроса.
Вот пример того, как написаны мои слои ...
public class CourseService
{
private readonly ICourseRepository _repo;
public CourseService(ICourseRepository repo)
{
_repo = repo;
}
public IEnumerable<Course> FindCoursesBy(string searchTerm)
{
var courses = _repo.FindBy(searchTerm);
var log = string.format("search for '{1}' returned {0} courses",courses.Count(),searchTerm);
_repo.LogCourseSearch(log);
//IMO the service layer should be calling Commit() on IUnitOfWork here...
return courses;
}
}
public class EFCourseRepository : ICourseRepository
{
private readonly ObjectContext _context;
public EFCourseRepository(IUnitOfWork unitOfWork)
{
_context = (ObjectContext)unitOfWork;
}
public IEnumerable<Course> FindBy(string text)
{
var qry = from c in _context.CreateObjectSet<tblCourse>()
where c.CourseName.Contains(text)
select new Course()
{
Id = c.CourseId,
Name = c.CourseName
};
return qry.AsEnumerable();
}
public Course Register(string courseName)
{
var c = new tblCourse()
{
CourseName = courseName;
};
_context.AddObject(c);
//the repository needs to call SaveChanges to get the primary key of the newly created entry in tblCourse...
var createdCourse = new Course()
{
Id = c.CourseId,
Name = c.CourseName;
};
return createdCourse;
}
}
public class EFUnitOfWork : ObjectContext, IUnitOfWork
{
public EFUnitOfWork(string connectionString) : base(connectionString)
{}
public void Commit()
{
SaveChanges();
}
public object Context
{
get { return this; }
}
}
В комментариях выше вы можете увидеть, где я чувствую, что «должен» фиксировать мои изменения, но я чувствую, что могу упустить из виду большую проблему, позволяя как уровню сервиса, так и реализации репозитория контролировать объем транзакций.
В дополнение к этому - когда моему хранилищу необходимо сохранить новый объект и вернуть его с новым первичным ключом без изменений, этого не произойдет, если я вызываю Commit из пользовательского интерфейса после того, как объект был возвращен. Поэтому хранилищу иногда нужно управлять единицей работы.
Можете ли вы увидеть какие-либо непосредственные проблемы с моим подходом?