SubSonic: магия и ORM

О чём это?

На днях передо мной стояла задача создания прототипа веб-приложения с определенным набором функций, в том числе, подразумевающих работу с данными. Набор инструментов я подобрал следующий:

  • ASP.NET MVC
  • SQLite

Набросав первое приближение модели предметной области, я озаботился её сохраняемостью и решил заняться выбором ORM:

  • LINQ to SQL насколько известно умеет работать только с Microsoft SQL Server
  • Entity Framework ещё не готов в пригодной версии
  • DBLinq вроде бы прекрасно работает со всеми известными RDBMS, однако отсутствие его популярности и низкая версия немного меня оттолкнули
  • О SubSonic я слышал краем уха, однако так и не имел тесного знакомства, на нём и решил остановится, фреймворк имеет в багаже уже 3юю версию, а так же известного создателя (Rob Conery)

Чем же хорош SubSonic?

SubSonic

Очень заинтересовали 5 минутные ролики о SubSonic:

http://subsonicproject.com/docs/The_5_Minute_Demo

http://subsonicproject.com/docs/Simple_Repo_5_Minute_Demo

Кстати SubSonic помимо того, что является ORM, так же предоставляет слой доступа к данным.

Итак в 3ей версии SubSonic мы имеем 2 сценария работы:

  • ActiveRecord – фактически повторяет классический для Ruby On Rails подход, в котором модель является моделью данных, т.е. знает о способах своей сохраняемости. Данный подход в случае SubSonic полезен в построении дата-ориентированных решений, вам достаточно просто сохранить в T4 шаблоне имя строки подключения к имеющейся у вас базе данных, остальное SubSonic сделает сам (генерирует соответствующие данным .NET-типы в вашем приложении)
  • SimpleRepository – более привычный для меня подход, подразумевает под собой абстракцию хранения данных под некоторым классом-коллекцией объектов.

Реализация обоих сценариев прозрачна с точки зрения подхода и реализует соответствующие паттерны PoEAA:

Как же я воспользовался SubSonic в своём приложении?

Я о определил интерфейс репозитория:

  public interface IRepository<T>
  {
    void Add(T entity);
    T FetchById(long id);
    IEnumerable<T> FetchAll(Expression<Func<T, bool>> predicate);
    IEnumerable<T> FetchAll();
    void Update(T entity);
    void Remove(T entity);
  }

Имплементация его имела следующий вид:

  public class EntityRepository : Domain.IRepository<Entity>
  {
    readonly IRepository _db;

    public ComputersRepository()
    {
      _db = SimpleRepositoryFactory.Create();
    }

    public void Add(Entity entity)
    {
      _db.Add(entity);
    }

    public Computer FetchById(long id)
    {
      return _db.Single<Entity>(x => x.Id == id);
    }

    public IEnumerable<Computer> FetchAll(Expression<Func<Entity, bool>> predicate)
    {
      return _db.Find(predicate);
    }

    public IEnumerable<Computer> FetchAll()
    {
      return _db.All<Entity>();
    }

    public void Update(Entity entity)
    {
      _db.Update(entity);
    }

    public void Remove(Entity entity)
    {
      _db.Delete<Entity>(entity.Id);
    }
  }

Как вы успели заметить производством SimpleRepository занимается фабрика:

  public class SimpleRepositoryFactory
  {
    public static SimpleRepository Create()
    {
      IDataProvider dataProvider = ProviderFactory.GetProvider(ConnectionString, "System.Data.SQLite");
      return new SimpleRepository(dataProvider, SimpleRepositoryOptions.RunMigrations);
    }

    protected static string ConnectionString
    {
      get
      {
        return "Data Source=data.db;Version=3;";
      }
    }
  }

Кстати, это всё, что нам понадобится, для работы со слоем сохранения. Давайте теперь разберёмся, что же именно будет делать SubSonic. Фактически он возмёт на себя все задачи по генерации базы данных и всех таблиц. Так же он предоставит все механизмы для доступа по-средствам Linq. Однако стоит иметь ввиду, что SubSonic SimpleRepository не умеет работать со сложными типами и ссылками на другие типы (однако это проблема решается благодаря Join’ам в запросах)

Интересной возможностью является возможность работы с «пакетами» данных:

IEnumerable<Post> posts=GetABunchOfNewPosts();
repo.AddMany(posts);
 
//update a post
repo.Update(post);
 
//update a bunch of posts in a transaction
IEnumerable<Post> posts=GetABunchOfNewPosts();
repo.UpdateMany(posts);
 
//delete a post
repo.Delete<Post>(key);
 
//delete a lot of posts
repo. DeleteMany <Post>(x=>x.Title.StartsWith("M"));
 
//delete posts using a transaction
IEnumerable<Post> posts=GetABunchOfNewPosts();
repo.DeleteMany(posts);

Проблема с пейджингом так же решена из коробочки:

//a PagedList of posts - using 10 per page
var posts=repo.GetPaged<Post>(0,10);
//sort by title
var posts=repo.GetPaged<Post>("Title",0,10);

Диагноз

Рекомендую SubSonic как лучшее решения доступа к данным для прототипирования

Реклама

6 комментариев on “SubSonic: магия и ORM”

  1. А если совсем без ORM?

  2. […] This post was mentioned on Twitter by butaji, Mykola Shestopal. Mykola Shestopal said: SubSonic: магия и ORM http://bit.ly/5THR7u #greader […]

  3. SubSonic: магия и ORM…

    Thank you for submitting this cool story — Trackback from progg.ru…

  4. А я еще год назад использовал Entity Framework для работы с SQLite…


Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s