Сохранить данные через веб-службу с помощью NHibernate?

В настоящее время у нас есть приложение, которое извлекает данные с сервера через веб-службу и заполняет DataSet. Затем пользователи API манипулируют им с помощью объектов, которые, в свою очередь, изменяют набор данных. Затем изменения сериализуются, сжимаются и отправляются обратно на сервер для обновления.

Однако я начал использовать NHibernate в проектах, и мне очень нравится отключенный характер объектов POCO. Проблема, с которой мы сталкиваемся сейчас, заключается в том, что наши объекты настолько привязаны к внутреннему DataSet, что их нельзя использовать во многих ситуациях, и в конечном итоге мы создаем повторяющиеся объекты POCO для передачи туда и обратно.

Batch.GetBatch() -> calls to web server and populates an internal dataset
Batch.SaveBatch() -> send changes to web server from dataset 

Есть ли способ достичь аналогичной модели, которую мы используем, когда весь доступ к базе данных осуществляется через веб-службу, но с использованием NHibernate?

Изменить 1

У меня есть частичное решение, которое работает и сохраняется через веб-службу, но имеет две проблемы.

  1. Мне нужно сериализовать и отправить всю свою коллекцию, а не только измененные элементы
  2. Если я попытаюсь повторно заполнить коллекцию после возврата моих объектов, все ссылки, которые у меня были, будут потеряны.

Вот мой пример решения.

Клиентская сторона

public IList<Job> GetAll()
{
    return coreWebService
      .GetJobs()
      .BinaryDeserialize<IList<Job>>();
}

public IList<Job> Save(IList<Job> Jobs)
{
    return coreWebService
             .Save(Jobs.BinarySerialize())
             .BinaryDeserialize<IList<Job>>();
}

На стороне сервера

[WebMethod]
public byte[] GetJobs()
{
    using (ISession session = NHibernateHelper.OpenSession())
    {
        return (from j in session.Linq<Job>()
                select j).ToList().BinarySerialize();
    }
}

[WebMethod]
public byte[] Save(byte[] JobBytes)
{
    var Jobs = JobBytes.BinaryDeserialize<IList<Job>>();

    using (ISession session = NHibernateHelper.OpenSession())
    using (ITransaction transaction = session.BeginTransaction())
    {
        foreach (var job in Jobs)
        {
            session.SaveOrUpdate(job);
        }
        transaction.Commit();
    }

    return Jobs.BinarySerialize();
}

Как видите, я каждый раз отправляю на сервер всю коллекцию, а затем возвращаю ее целиком. Но я получаю замененную коллекцию вместо объединенной / обновленной коллекции. Не говоря уже о том, что пересылка всех данных туда и обратно кажется крайне неэффективной, если только часть их может быть изменена.

Изменить 2

Я видел в сети несколько ссылок на почти прозрачный постоянный механизм. Я не совсем уверен, сработают ли они, и большинство из них выглядят экспериментально.

Мне сложно найти замену модели DataSet, которую мы используем сегодня. Причина, по которой я хочу уйти от этой модели, заключается в том, что требуется много работы, чтобы привязать каждое свойство каждого класса к строке / ячейке набора данных. Кроме того, это также тесно связывает все мои занятия вместе.


person Nathan Palmer    schedule 26.10.2009    source источник
comment
Какая версия .NET является вашим клиентом и сервером? Вам когда-нибудь понадобится общаться с клиентом без .net? (Или насколько сильно вы хотите быть связаны?)   -  person Aaron Fischer    schedule 30.10.2009
comment
Версия 3.5, и нам не нужно взаимодействовать ни с чем, кроме .NET. Насколько я понимаю, он может быть полностью привязан к .NET. Строим клиент и сервер.   -  person Nathan Palmer    schedule 31.10.2009


Ответы (2)


Я лишь бегло рассмотрел ваш вопрос, так что простите меня, если мой ответ недальновиден, но вот что:

Я не думаю, что вы можете логически уйти от сопоставления объекта домена с DTO.

Используя объекты домена по сети, вы плотно связываете своего клиента и сервис, и одна из причин, по которой сервис должен быть в первую очередь, заключается в том, чтобы способствовать слабой связи. Так что это насущная проблема.

Вдобавок к этому вы получите хрупкий интерфейс логики домена, в котором вы не сможете вносить изменения на стороне службы, не нарушая работу вашего клиента.

Я подозреваю, что лучше всего было бы реализовать слабо связанный сервис, который реализует REST / или какой-либо другой слабо связанный интерфейс. Вы можете использовать такой продукт, как automapper, чтобы упростить и упростить преобразование, а также при необходимости сгладить структуры данных.

На данный момент я не знаю никакого способа по-настоящему сократить многословие, связанное с созданием слоев интерфейса, но, работая над большими проектами, которые не прилагали усилий, я могу честно сказать, что экономия того не стоила.

person Gary    schedule 08.12.2011

Я думаю, ваша проблема связана с этой проблемой:

http://thatextramile.be/blog/2010/05/why-you-shouldnt-expose-your-entities-through-your-services/

Вы собираетесь или не собираетесь отправлять ORM-Entities по сети?

Поскольку у вас архитектура, ориентированная на службы ... Я (как и автор) не рекомендую эту практику.

Я использую NHibernate. Я называю эти ORM-объекты. Это модель POCO. Но у них есть «виртуальные» свойства, допускающие отложенную загрузку.

Однако у меня также есть некоторые DTO-объекты. Это тоже POCO. У них нет свойств, удобных для ленивой загрузки.

Так что я много "конвертирую". Я гидратирую ORM-Entities (с NHibernate) ... а затем конвертирую их в Domain-DTO-Objects. Да, поначалу воняет.

Сервер отправляет доменные объекты DTO. НЕТ ленивой загрузки. Я должен заполнить их "правильной" моделью "Goldie Locks". Ака, если мне нужны Родители с одним уровнем детей, я должен знать это заранее и отправлять объекты Domain-DTO таким образом, с правильным количеством гидратации.

КОГДА я отправляю обратно объекты Domain-DTO (от клиента к серверу), я должен отменить процесс. Я конвертирую объекты Domain-DTO в ORM-Entities. И разрешите NHibernate работать с ORM-объектами.

Поскольку архитектура "отключена", я делаю много (NHiberntae) вызовов ".Merge ()".

        // ormItem is any NHibernate poco
        using (ISession session = ISessionCreator.OpenSession())
        {
            using (ITransaction transaction = session.BeginTransaction())
            {
                session.BeginTransaction();
                ParkingAreaNHEntity mergedItem = session.Merge(ormItem);
                transaction.Commit();
            }
        }

.Merge - замечательная вещь. Entity Framework его нет. Бу.

Это много настроек? да. Думаю, это идеально? Нет.

Тем не мение. Поскольку я отправляю в ORM очень простые DTO (Poco), которые не «приправлены», у меня есть возможность переключать ORM, не уничтожая мои контракты во внешний мир.

Мой уровень данных может быть ADO.NET, EF, NHibernate или чем-нибудь еще. Я должен написать «Конвертеры», если я переключаюсь, и код ORM, но все остальное изолировано.

Многие со мной спорят. Они сказали, что я слишком много делаю, и ORM-Entities в порядке.

Опять же, мне нравится «разрешить ленивую загрузку». И я предпочитаю изолировать свой уровень данных. Мои клиенты не должны знать или заботиться о моем выбранном уровне данных / организации.

Между EF и NHibernate есть достаточно тонких различий (или некоторых не очень тонких), чтобы испортить план игры.

Мои объекты Domain-DTO выглядят на 95% как мои ORM-объекты? Ага. Но это те 5%, которые могут вас обмануть.

Переход от DataSet, особенно если они заполнены из хранимых процедур с большим количеством бизнес-логики в TSQL, нетривиально. Но теперь, когда я занимаюсь объектной моделью и НИКОГДА не пишу хранимую процедуру, которая не является простыми функциями CRUD, я бы никогда не вернулся.

И я ненавижу проекты обслуживания с voodoo TSQL в хранимых процедурах. Уже не 1999 год. Ну, в большинстве мест.

Удачи.

PS Без .Merge (в EF) вот что вам нужно делать в отключенном мире: (boo microsoft)

http://www.entityframeworktutorial.net/EntityFramework4.3/update-many-to-many-entity-using-dbcontext.aspx

person granadaCoder    schedule 14.04.2014
comment
Так что я могу понять, что здесь нельзя раскрывать сущности через мои сервисы. Однако одна важная часть, которой я пытался достичь, заключалась в отправке на сервер только различий, а не всего объекта. Это было просто (даже если это было связано) с использованием DataSets. - person Nathan Palmer; 16.05.2014