7

好吧,我一直在尝试将我的模型转换为使用 LINQ,但不想丢弃我当前的 DTO 及其分散在域中的接口。

我设法找到了这篇博客文章,它很好地概述了这个过程:

在 LINQ To SQL 中实现 POCO

我设法让对象的记录检索正常工作,但是,由于我的模型的嵌套性质,我似乎无法为子对象添加工作。也就是说,如果我创建一个子对象,并设置对所需父对象的引用,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) 设置为 null。

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;

和;

    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>

那么,谁能指出我正确的方向?我已经找了好几个小时了...

编辑:

这是我的测试失败的堆栈跟踪:

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"

XML 映射中的 Selections 外键已删除外键错误,但现在我在 Selections 的其中一个子对象上获得了一个空引用,说它对 Selections 的引用为空,即使在未设置任何变量的情况下初始化 Selections (外键之外)。我什至尝试创建一个子对象,并正确设置它的引用,但仍然收到此错误:

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 个市场有很多选择)等等。

4

5 回答 5

4

我想问题出在你的测试方法上。您使用 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);
}
于 2008-11-18T09:30:39.157 回答
2

只是一个猜测,但它可能就在这里

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

当您设置为 Market 的值为 null 时会发生什么?最后一行将无效,因为它无法解析 null.MID。也许你的二传手需要这个:

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

此外,您的 MID 必须可以为空

int? MID
于 2008-11-18T09:32:26.640 回答
2

对于您的新问题;对 Price 的选择属性进行空分配时会出现问题。你是通过你的代码做到的吗?您能否再次给出您遇到异常的代码部分?我的意思是分配给价格实体...

根据评论编辑:我猜这是因为我们之前在 GeekyMonkeys 帖子中提到的空控制异常。在 Selection 类的初始化中,Price 属性需要设置为 null,但是当分配 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;
          }
       }
    }
}
于 2008-11-18T12:57:43.090 回答
2

我知道已经有一段时间了,您可能已经解决了这个问题,但也许还没有……

我假设您的数据结构与此类似:

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();
于 2010-02-04T23:39:48.647 回答
0

我建议将您的代码发送给 Sidar Ok。他是个好人,会为你指明正确的方向。或者至少在他的博客上发表评论,指出他在这里的问题。

于 2008-11-18T09:29:51.170 回答