Сериализация Linq2Sql поверх Wcf - ошибка или недоразумение? - PullRequest
0 голосов
/ 29 августа 2009

Работа с Linq2Sql в качестве драйвера для службы Wcf. Пойдем снизу вверх ...

Внизу у нас есть метод, который поражает Linq2Sql ...

public virtual void UpdateCmsDealer(CmsDealer currentCmsDealer)
{
    this.Context.CmsDealers.Attach(currentCmsDealer, 
             this.ChangeSet.GetOriginal(currentCmsDealer));
}

Это используется моей службой Wcf как таковой ...

public bool UpdateDealer(CmsDealer dealer)
{
    try
    {
        domainservice.UpdateCmsDealer(dealer);
        return true;
    }
    catch
    {
        return false;
    }
}

И вызывается из моего клиентского кода Wpf таким образом (псевдокод ниже) ...

[...pull the coreDealer object from Wcf, it is a CmsDealer...]
[...update the coreDealer object with new data, not touchign the relation fields...]
try
{
    contextCore.UpdateDealer(coreDealer);
}
catch (Exception ex)
{
    [...handle the error...]
}

Теперь тип CmsDealer имеет> 1 <отношение ключа foriegn, он использует поле «StateId» для связи с таблицей CmsItemStates. Так что да, в приведенном выше заполняется coreDealer.StateId, и я могу получить доступ к данным на coreDealer.CmsItemState.Title показывает мне плитку соответствующего состояния. </p>

Теперь, вот в чем дело ... если вы закомментируете строку ...

domainservice.UpdateCmsDealer(dealer);

В сервисе Wcf он все еще бомбит, за исключением нижеуказанного исключения, которое указывает мне, что на самом деле это не проблема Linq2Sql, а скорее проблема Linq2Sql over Wcf.

"System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException was unhandled by user code
  Message="Operation is not valid due to the current state of the object."

InnerException НЕДЕЙСТВИТЕЛЕН. Конечный результат всего этого, когда он попадает в обработчик ошибок (Catch ex bloc), сообщение об исключении будет жаловаться на десериализатор. Когда я могу отладить отладку, фактический код, вызывающий ошибку, - это фрагмент кода модели CmsDealer, созданный Linq2Sql.

[Column(Storage="_StateId", DbType="UniqueIdentifier NOT NULL")]
public System.Guid StateId
{
    get
    {
        return this._StateId;
    }
    set
    {
        if ((this._StateId != value))
        {
            if (this._CmsItemState.HasLoadedOrAssignedValue)
            {
                throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException();
            }
            this.OnStateIdChanging(value);
            this.SendPropertyChanging();
            this._StateId = value;
            this.SendPropertyChanged("StateId");
            this.OnStateIdChanged();
        }
    }
}

Короче говоря, может показаться, что кое-что происходит "под прикрытием", что нормально, но документация отсутствует. Черт возьми, Google для "ForeignKeyReferenceAlreadyHasValueException" почти ничего не дает :))

Я бы предпочел продолжить работу с объектами Linq2Sql непосредственно через Wcf. Я мог бы, если необходимо, создать плоский прокси-класс, который не имел никакой связи, отправить его по проводам в Wcf, а затем использовать его в качестве источника данных для обновления на стороне сервера ... но, очевидно, это требует больших усилий, когда это очевидно. предполагаемый сценарий ... верно?

Спасибо!

Ответы [ 2 ]

2 голосов
/ 17 марта 2011

Сериализатор по умолчанию сначала устанавливает State, который устанавливает StateId. После этого он попытается установить сериализованный StateId, а затем выдается исключение.

Проблема в том, что вы не указали, что хотите, чтобы ваши классы были украшены атрибутом DataContract.

Перейдите в свойства вашего LinqToSqlGenerator и установите Режим сериализации на Однонаправленный

Это приведет к тому, что инструмент добавит атрибут DataMember к необходимым свойствам, и вы увидите, что StateId не будет DataMember, поскольку он будет автоматически установлен, когда свойство State будет установлено при десериализации.

1 голос
/ 29 августа 2009

Вероятно, ошибка связана с тем, что что-то изменило значение fk после того, как оно было изначально установлено - вы уверены, что у вас нет какого-то специального кода инициализации, который мог бы изначально устанавливать значение?

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...