Помощь, необходимая для операций LINQ To SQL (вставка / обновление) с вложенными POCO - PullRequest
7 голосов
/ 18 ноября 2008

Хорошо, я пытался преобразовать свою модель для использования LINQ, но не хотел выбрасывать мои текущие DTO и их интерфейсы, которые разбросаны по домену.

Мне удалось найти этот пост в блоге, который довольно хорошо описал процесс:

Достижение POCO в LINQ To SQL

Мне удалось получить извлечение записей для объектов, работающих должным образом, однако, из-за вложенной природы моей модели, я не могу заставить дополнение работать с дочерними объектами. То есть, если я создаю дочерний объект и устанавливаю ссылку на нужный родительский объект, LINQ to SQL по-прежнему выдает исключение, указывающее, что ссылка дочернего элемента на родительский объект является нулевой. Если я пытаюсь добавить простой старый родительский объект, это успешно, но добавление дочерних объектов непосредственно терпит неудачу

Вот мой провальный тест:

    [Test]
    public void AddSelectionShouldAddSelectionToMarket()
    {
        Market market = (Market) new Repository().GetMarket(1);

        Selection selection = new Selection();
        selection.Market = market;

        new Repository().AddSelection(selection);

        Assert.IsTrue(selection.SID > 0);
    }

Вот сообщение об ошибке:

System.InvalidOperationException: была предпринята попытка удалить связь между рынком и выбором. Однако один из внешних ключей отношения (Selection.MID) не может быть установлен равным нулю.

Соответствующие части 2 объекта:

[DataContract]
public class Selection : ISelection
{
    private int mID;
    [DataMember]
    public int MID
    {
        get { return this.mID; }
        set { this.mID = value; }
    }

    private Market market;
    [DataMember]
    public Market Market
    {
        get { return this.market; }
        set
        {
            this.market = value;
            this.mID = value.MID;
        }
    }
}

[DataContract]
public class Market : IMarket
{
    private int mID;
    [DataMember]
    public int MID
    {
        get { return this.mID; }
        protected set { this.mID = value; }
    }

    private List<Selection> selections;
    [DataMember]
    public List<Selection> Selections
    {
        get { return this.selections; }
        set
        {
            this.selections = value;
            // For LINQ
            foreach (Selection selection in selections)
            {
                selection.MID = mID;
                selection.Market = this;
            }
        }
    }
}

Мой код DA:

        MarketsDataContext context = new MarketsDataContext();

        DataLoadOptions options = new DataLoadOptions();
        options.LoadWith<Selection>(s => s.Prices);
        options.LoadWith<Market>(m => m.Selections);

        context.LoadOptions = options;
        return context;

и *; 1024 *

    public void AddSelection(ISelection selection)
    {
        using (MarketsDataContext context = MarketsDataContext.GetContext())
        {
            context.Selections.InsertOnSubmit((Selection) selection);
            context.SubmitChanges();
        }
    }

И, наконец, мое сопоставление XML:

  <Table Name="dbo.Markets" Member="Markets">
    <Type Name="Market">
      <Column Name="MID" Member="MID" Storage="mID" DbType="Int NOT NULL" IsPrimaryKey="true" IsDbGenerated="true" AutoSync="OnInsert" />
      <Association Name="FK_Market-Selections" Member="Selections" Storage="selections" ThisKey="MID" OtherKey="MID" DeleteRule="NO ACTION"  />
    </Type>
  </Table>

  <Table Name="dbo.Selections" Member="Selections">
    <Type Name="Selection">
      <Column Name="SID" Member="SID" Storage="sID" DbType="Int NOT NULL" IsPrimaryKey="true" IsDbGenerated="true" AutoSync="OnInsert" />
      <Column Name="MID" Member="MID" Storage="mID" DbType="Int NOT NULL" />
      <Association Name="FK_Market-Selections" Member="Market" Storage="market" ThisKey="MID" OtherKey="MID" IsForeignKey="true" />
    </Type>
  </Table>

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

Edit:

Вот моя трассировка стека для моего теста:

at System.Data.Linq.ChangeTracker.StandardChangeTracker.StandardTrackedObject.SynchDependentData()
at System.Data.Linq.ChangeProcessor.ValidateAll(IEnumerable`1 list)
at System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode)
at System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
at System.Data.Linq.DataContext.SubmitChanges()
at BetMax.DataModel.Repository.AddSelection(ISelection selection) in Repository.cs: line 68
at BetMax.DataModel.Test.ModelTest.AddSelectionShouldAddSelectionToMarket() in ModelTest.cs: line 65 

И мой метод GetMarket:

    public IMarket GetMarket(int MID)
    {
        Market market;
        using (MarketsDataContext context = MarketsDataContext.GetContext())
        {
            market = context.Markets.Single(m => m.MID == MID);
        }
        return market;
    }

Редактировать 2:

Ну, добавив

DeleteOnNull="true"

для внешнего ключа Selections в сопоставлении XML устранена ошибка внешнего ключа, но теперь я получаю нулевую ссылку на один из дочерних объектов Selections, говоря, что его ссылка на Selection является нулевой, даже если Selection инициализируется ни с одним его переменные установлены (вне внешних ключей). Я даже пытался создать дочерний объект и правильно установить его ссылки, но все еще получаю эту ошибку:

System.NullReferenceException: Object reference not set to an instance of an object.
at BetMax.DTO.Price.set_Selection(Selection value) in Price.cs: line 25
at System.Data.Linq.Mapping.PropertyAccessor.Accessor`3.SetValue(ref T instance, V value)
at System.Data.Linq.Mapping.MetaAccessor`2.SetBoxedValue(ref Object instance, Object value)
at System.Data.Linq.ChangeProcessor.ClearForeignKeysHelper(MetaAssociation assoc, Object trackedInstance)
at System.Data.Linq.ChangeProcessor.ClearForeignKeyReferences(TrackedObject to)
at System.Data.Linq.ChangeProcessor.PostProcessUpdates(List`1 insertedItems, List`1 deletedItems)
at System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode)
at System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
at System.Data.Linq.DataContext.SubmitChanges()
at BetMax.DataModel.Repository.AddSelection(ISelection selection) in Repository.cs: line 68
at BetMax.DataModel.Test.ModelTest.AddSelectionShouldAddSelectionToMarket() in ModelTest.cs: line 69 

Цена - это еще один объект, построенный так же, как этот Выбор, связанный с Рынком (1 выбор имеет много цен, 1 рынок имеет много выборов) и т. Д. И т. Д.

Ответы [ 5 ]

4 голосов
/ 18 ноября 2008

Полагаю, проблема в вашем методе тестирования. Вы создали репозиторий с DataContext, но отправили его с другим.

[Test]
public void AddSelectionShouldAddSelectionToMarket()
{
    Market market = (Market) new Repository().GetMarket(1);

    Selection selection = new Selection();
    selection.Market = market;

    new Repository().AddSelection(selection);

    Assert.IsTrue(selection.SID > 0);
}

Создайте репозиторий и используйте его в методе тестирования.

[Test]
public void AddSelectionShouldAddSelectionToMarket()
{
    Repository repository = new Repository();
    Market market = (Market) repository.GetMarket(1);

    Selection selection = new Selection();
    selection.Market = market;

    repository.AddSelection(selection);

    Assert.IsTrue(selection.SID > 0);
}
2 голосов
/ 05 февраля 2010

Я знаю, что это было давно, и вы, вероятно, уже решили проблему, но, возможно, нет ...

Я предполагаю, что ваша структура данных похожа на эту:

Market
======
Market_ID      int not null identity (1, 1)


Selection
=========
Selection_ID   int not null identity (1, 1)
Market_ID      int (FK to Market)
Selection_Name varchar(50)

Чтобы добавить новый Рынок и новый Выбор одновременно:

Selection selection = new Selection();
Market market = new Market();

market.Selections.Add(selection);
DataContext.Markets.InsertOnSubmit(market);
DataContext.SubmitChanges();

Чтобы добавить новый выбор к существующему рынку:

Selection selection = new Selection();
Market market = DataContext.Markets.Where(a => a.Market_ID == 7).Single();

market.Selections.Add(selection);
DataContext.SubmitChanges();

Чтобы обновить первый выбор на рынке:

Selection selection = DataContext.Markets.Where(a => a.Market_ID == 7).Selections.First();

selection.Selection_Name = "New Name";
DataContext.SubmitChanges();
2 голосов
/ 18 ноября 2008

за ваш новый номер; Проблема возникает при нулевом назначении для свойства выбора Price. Вы сделали это с помощью своего кода? Не могли бы вы еще раз дать часть кода, которую вы получили за исключением? Я имею в виду присвоение ценовой сущности ...

Редактировать в соответствии с комментарием: Я предполагаю, что это из-за исключения управления нулем, как мы упоминали ранее в сообщении GeekyMonkeys. При инициализации класса Selection свойство Price должно быть установлено как null, но когда ему присваивается значение null, оно выбрасывает нулевую ссылку. Таким образом, вы должны сделать нулевой контроль в наборе свойства цены.

private List<Price> prices
[DataMember]
public List<Price> Prices
{
    get { return this.prices; }
    set
    {
        if(value != null)
        {
          this.pricess = value;
          // For LINQ             
          foreach (Price price in prices)
          {
            price.MID = mID;
            price.Selection = this;
          }
       }
    }
}
2 голосов
/ 18 ноября 2008

Просто предположение, но это может быть здесь

public Market Market
{
    get { return this.market; }
    set
    {
        this.market = value;
        this.mID = value.MID;
    }
}

Что происходит, когда значение, установленное для Market, равно нулю? Последняя строка этого будет недействительной, поскольку она не сможет разрешить null.MID. Может быть, вам нужно это для вашего сеттера:

    set
    {
        this.market = value;
        this.mID = (value == null) ? null : value.MID;
    }

Также ваш MID должен быть обнуляемым

int? MID
0 голосов
/ 18 ноября 2008

Я бы посоветовал отправить ваш код в Sidar Ok. Он хороший парень и укажет вам правильное направление. Или, по крайней мере, оставьте комментарий в своем блоге, указывая ему на ваш вопрос здесь.

...