2009-05-11 2 views
1

Мы используем Linq to SQL для чтения и записи наших объектов домена в базу данных SQL Server.Восстановление объектов домена из базы данных: проблема с идентификацией

Мы предоставляем ряд услуг (через WCF) для выполнения различных операций. В конце концов, реализация этих операций состоит из трех этапов: восстановление необходимых объектов домена из базы данных; выполнить операцию над объектами домена; сохраняйте (теперь измененные) объекты домена обратно в базу данных.

Проблема в том, что иногда есть два или более экземпляра одного и того же объекта сущности, что может привести к несогласованности при сохранении объектов обратно в db. Немного выдуманный пример:

public void Move(string sourceLocationid, destinationLocationId, itemId); 

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

Эта проблема теперь «решена», проверяя ее вручную, т. Е. Мы восстанавливаем первое местоположение, проверяем, отличается ли второй идентификатор от него, и если это повторяет второй и т. Д. Это непротиворечиво и подвержено ошибкам.

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

Моей идеей было бы сделать объект DomainContext за операцию, которая отслеживает и кэширует объекты домена, используемые в этом конкретном методе. Вместо того, чтобы восстанавливать и сохранять отдельные объекты домена, такой объект будет восстановлен и сохранен в целом (возможно, с использованием репозиториев), и он может действовать как кеш для объектов домена, используемых в этой конкретной операции.

В любом случае, похоже, что это распространенная проблема, так как это обычно происходит? Что вы думаете об этой идее?

ответ

1

DataContext в Linq-To-Sql поддерживает концепцию Identity Map и должен кэшировать объекты, которые вы извлекаете. Объекты будут отличаться только в том случае, если вы используете , а не, используя тот же DataContext для каждой операции GetById().

Объекты Linq to Sql действительно не действуют за пределами срока службы DataContext. Вы можете найти Rick Strahl's Linq to SQL DataContext Lifetime Management хороший фон прочитанный.

Кроме того, ORM не несет ответственности за логику в домене. Это не будет запрещать ваш пример Move. Это решение для домена, чтобы решить, что это значит. Он игнорирует это? или это ошибка?Это ваша логика домена, и это необходимо реализовать на границе службы, которую вы создаете.

Однако Linq-To-Sql знает, когда объект изменяется, и из того, на что я смотрел, он не будет записывать изменение, если вы повторно назначили одно и то же значение. например если Item.LocationID = 12, установка идентификатора location в 12 снова не приведет к обновлению при вызове SubmitChanges().

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

public void Move(string sourceLocationId, destinationLocationId, itemId) 
{ 
    if(sourceLocationId == destinationLocationId) 
     return; 

    using(DataContext ctx = new DataContext()) 
    { 
     Item item = ctx.Items.First(o => o.ItemID == itemId); 
     Location destination = 
      ctx.Locations.First(o => o.LocationID == destinationLocationID); 
     item.Location = destination; 

     ctx.SubmitChanges(); 
    } 
} 

Еще одна небольшая точка, которая может или не может быть применимо, это вы должны сделать свои интерфейсы, как коренастый, насколько это возможно. например Если вы, как правило, собираетесь выполнять 10 операций перемещения одновременно, лучше вызвать один метод обслуживания, чтобы выполнить все 10 операций одновременно, а не 1 операцию за раз. ref: chunky vs chatty

1

Многие ORM используют две концепции, которые, если я вас понимаю, адресуют вашу проблему. Первым и наиболее релевантным является Контекст, который отвечает за то, что только один объект представляет собой сущность (строка таблицы базы данных, в простом случае), не сколько раз или путей, которые она запрашивает из базы данных. Вторая - это Единица работы; это гарантирует, что обновления базы данных для группы объектов либо все будут успешными, либо все сбой.

Оба они реализованы с помощью ORM, с которым я больше всего знаком (LLBLGen Pro), однако я считаю, что NHibernate и другие также реализуют эти концепции.

Смежные вопросы