Мои первые попытки использовать Test Driven Development закончились обычными проблемами с доступом к данным. Почти сразу выяснилось, что:
1. Невозможно использовать настоящую базу данных для запуска тестов. Каждый тест не должен зависеть от результатов других тестов. На практике это означает что каждый тест должен выполняться на чистой базе (в худшем случае), или что каждый тест должен быть обернут в транзакцию, с откаткой после выполнения.
2. Невозможно заменить весь код доступа к данным mock-ами. На самом деле, можно попробовать, но это привязывает тесты к конкретной реализации функционала. Вы вынуждены создавать mock для каждого обращения к DAL. Вы так же вынуждены изменять тесты при рефакторинге, что усложняет разработку сопровождение.
Общепринятое решение этих проблем – использование шаблонов Persistence Ignorance (PI) и Repository. Достаточно погуглить “IQueryable Repository”и вы найдете чуть более 9000 упоминаний чего-то вроде:
interface IRepository
{
IQueryable<T> All<T>();
void Insert<T>(T entity);
void Update<T>(T entity);
void Delete<T>(T entity);
}
…и множество реализаций этого интерфейса поверх LINQ To SQL. Несмотря на разнообразие, практически все они реализуют все один и тот же тип шаблона Repository - “Plain old CLR object” Repository. Это означает, что на базовый шаблон они накладывают довольно сильные ограничения.
Самое серьезное – то, что объекты должны быть “плоскими” в худшем смысле этого слова. Вы не можете заставить POCO Repository загрузить связи между объектами. Вы не можете написать код вроде:
repository.All<Project>()
.Where(p => p.Tasks.Count > 10);
В мире POCO связей вообще не существует! Одну короткую строчку кода вам придется заменить вот этим:
var projectIds = repository.All<Task>()
.GroupBy(t => t.ProjectId)
.Where(gr => gr.Count() > 10)
.Select(gr => gr.Key)
.ToList();
repository.All<Project>()
.Where(p => projectIds.Contains(p.Id));
Даже такой простой пример раздувается до двух запросов, с использованием IN. Написав такой мегакод пару раз, я решил что нужно найти способ запихнуть этот запрос назад в одну строчку. И при этом сохранить поддержку Persistence Ignorance.
Осталось придумать лишь еще одну реализацию шаблона Repository, которая:
1. Полностью поддерживает связи (Associations). Она должна поддерживать выполнение кода вроде:
repository.All<Task>()
.Where(t =>
t.Project.Customer.Name.StartsWith("a"));
2. Поддерживает загрузку связанных объектов (Deep Load). Она должна уметь загружать одиночные и множественные зависимости по требованию.
// задачи, со свойством Project установленным в null
repository.All<Task>();
// задачи с загруженным свойством Project
repository.All<Task>()
.LoadWith(t => t.Project);
// задачи в будущих проектах
// свойство Project не загружено (null)
repository.All<Task>()
.Where(t => t.Project.StartDate > DateTime.Today);
3. Поддерживает перехват запросов (Query Interception), для красивых глобальных фильтров
// задачи видимые текущему пользователю
// поведение по умолчанию
repository.All<Task>();
// все задачи, без учета прав пользователя
repository.All<Task>()
.IgnorePermissions();
// сообщения со статусом != Deleted
// поведение по умолчанию
repository.All<Message>();
// только “удаленные” сообщения
repository.All<Message>()
.Deleted();
// все сообщения
repository.All<Message>()
.IncludeDeleted();
4. Позволяет легко переключиться между LINQ To SQL и In-Memory реализациями, одним ключом в конфиге. Изначально ориентирована на использование IoC/DI.
Мы попытались решить эти проблемы и сделать “старые плоские” объекты не настолько плоскими и старыми. Код и примеры выложены на http://lsda.codeplex.com/. Этот блог будет постепенно расти до полноценной документации
Отзывы, пожелания и патчи приветствуются.
October 21st, 2009 - 11:16 pm
Жаль что вы только начали.
Как раз ищу подобную библиотеку.
October 22nd, 2009 - 9:45 am
2build_your_web: начали - понятие осносительное. мы на нем уже штук 5 проектов сдали.
Попробуй забрать source code с кодеплекса, там есть базовые примеры. Постараюсь до конца недели зарелизить и выложить более полные семплы.
December 2nd, 2009 - 8:36 am
а где можно посомтреть конкретные примеры, где видно преимущества Repository?
July 23rd, 2010 - 12:47 pm
Честно, неплохая новость
July 24th, 2010 - 2:16 pm
Вот именно с этой статьи начинаю читать Ваш блог. Плюс один подписчик
July 25th, 2010 - 2:20 am
” Lesbian’s World ” It’s Our Time Now
July 25th, 2010 - 2:22 am
” Lesbian’s World ” It’s Our Time Now
July 25th, 2010 - 12:09 pm
Класс! Очень понравилось
July 26th, 2010 - 4:05 pm
На каком-то сайте я уже читал почти такую же подборку инфы, но все равно спасибо
July 26th, 2010 - 11:50 pm
Да уж, хорошо написано.
July 27th, 2010 - 12:11 pm
Очень просто на словах а в деле, многое несоответсвует, не так всё радужно!
July 30th, 2010 - 10:32 am
Amazing, truly excellent information. Your blog is really awesome. I bookmarked this and will come back once again. . . .
July 30th, 2010 - 10:32 am
I tried to subscribe to your rss feed, but had a problem adding it to google reader. Could you please check this out.
August 1st, 2010 - 4:19 pm
Побольше б таких штук…Beautiful!
August 1st, 2010 - 5:35 pm
Автор, отлично. Только не пихайте где только можно рекламу
August 2nd, 2010 - 12:46 am
А Вы не задумывались о том, чтобы параллельно завести еще один блог, на смежную тему? У Вас неплохо получается
August 2nd, 2010 - 4:36 pm
Классно, вещь полезная!
August 3rd, 2010 - 4:59 am
Огромное человеческое спасбо!
August 3rd, 2010 - 4:11 pm
A weblog with information very exciting, congratulations to the writer!
August 3rd, 2010 - 7:19 pm
Интернет пишется с большой буквы внутри предложения, если что. И сотые не с точкой, а с запятой. Это по стандарту. А так неплохо все, просто вэри гуд!
August 4th, 2010 - 4:24 am
Horoshaya infa!
August 5th, 2010 - 10:55 pm
блин, почему так мало хороших блогов осталось? этот вне конкуренции
August 6th, 2010 - 1:05 am
Побольше б таких штук…Beautiful!
August 8th, 2010 - 4:40 am
Действительно полезняк! А то сколько не лазишь по нету сплошное бла бла бла. Но не тут, и это радует!
August 9th, 2010 - 11:14 pm
Слушай, аффтар, а ты сам писал или перписывал откуда-то?
August 11th, 2010 - 1:10 pm
Thanks for taking the time to share this, I feel strongly about it and love reading more on this topic. If possible, as you gain knowledge, would you mind updating your blog with more information? It is extremely helpful for me.
August 12th, 2010 - 6:18 am
Amazing, truly excellent information. Your blog is really awesome. I bookmarked this and will come back once again. . . .
August 12th, 2010 - 12:52 pm
Сугубо мое имхо - ты не можешь определиться с выбором. Удачи, подумай над этим.
August 13th, 2010 - 11:56 am
Хороший пост, всегда с удовольствием Вас читаю
August 14th, 2010 - 9:09 am
JJ, do you even know what free-market competition is? “It’s ridiculous to assume liberals don’t believe in free market competition. We believe in free market competition with a level playing field for everyone.” That’s like saying the Lakers and the Cavaliers are too good, so they have to give Lebron and Kobe to the Nets and the T’wolves, so that everyone can “compete” on a “level playing field.”
August 14th, 2010 - 12:55 pm
I don’t agree. But still good post.
August 16th, 2010 - 6:47 am
Полностью с Вами согласна, примерно неделю назад написала про этоже в своем блоге!
August 17th, 2010 - 11:24 am
Прелестно) Хм… забавненько
August 17th, 2010 - 3:40 pm
I don”t think so…
August 19th, 2010 - 11:27 pm
Also if it does have a chance of working do I have to go google for the needed demo or is it still hosted by Sony?
August 19th, 2010 - 11:51 pm
Useful information, thank you. I’ll be glad to see you on my site.
August 20th, 2010 - 1:28 am
I enjoyed reading your post. It’s very engaging and quite useful for me. Wish to get some more information though.
August 20th, 2010 - 1:40 pm
I always learn something new, thanks for sharing this article.
August 21st, 2010 - 10:20 pm
Я внимательно читал второй абзац и не вкурил суть изложенного
August 22nd, 2010 - 6:25 am
Thanks for the read, I will bookmark it and come back later to check out some of your other posts =)
August 23rd, 2010 - 3:05 pm
Хотелось бы что-то наваять в комментах креативного, но мысль не складывается, так что просто зачОт
August 24th, 2010 - 12:36 am
Да довольно таки прикольно!
August 25th, 2010 - 5:34 pm
I will visit your blog regularly for some latest post.
August 26th, 2010 - 11:30 pm
Only want to say your article is as tonishing. The clearness in your post is simply spectacular and i can take for granted you are an expert on this field. Well with your permission allow me to grab your rss feed to keep up to date with succeeding post. Thanks a million and please keep up the ac complished work.
August 29th, 2010 - 7:19 am
ТС, не стоит обольщаться.
PS: А в целом не понятен общий смысл.
August 30th, 2010 - 12:33 am
Just a fast hello and also to thank you for discussing your tips on this page. I wound up in your weblog right after researching physical fitness associated points on Yahoo… guess I lost track of what I had been performing! Anyway I’ll be back once more in the long term to verify out your blogposts down the road. Thanks!
August 31st, 2010 - 5:10 am
You really make it seem so easy with your presentation but I find this topic to be really something which I think I would never understand. It seems too complicated and very broad for me. I am looking forward for your next post.
August 31st, 2010 - 1:18 pm
I would like to thank you for the efforts you have made in writing this article. I am hoping the same best work from you in the future as well. In fact your creative writing abilities has inspired me to start my own BlogEngine blog now. Really the blogging is spreading its wings rapidly. Your write up is a fine example of it.
September 1st, 2010 - 8:30 am
Nice site, I just dugg this keep up the good work!. . . . . .
September 2nd, 2010 - 7:35 am
great thing all of us gots the internetz