代码之家  ›  专栏  ›  技术社区  ›  mwjackson

使用嵌套poco的linq-to-sql操作(插入/更新)所需的帮助

  •  7
  • mwjackson  · 技术社区  · 16 年前

    好吧,我一直在尝试将我的模型转换为使用linq,但是我不想丢弃我当前的dto和它们分散在域中的接口。

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

    Achieving POCOs in 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);
        }
    

    以下是错误消息:

    试图消除市场和选择之间的关系。但是,关系的外键之一(selection.mid)不能设置为空。

    两个对象的相关部分:

    [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>
    

    那么,有人能告诉我正确的方向吗?我已经找了好几个小时了…

    编辑:

    这是我测试失败的stacktrace:

    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映射中的to selection s外键已经消除了外键错误,但是现在我在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 
    

    价格是另一个对象,它的构造与选择与市场(一个选择有多个价格,一个市场有多个选择)等有关。

    5 回复  |  直到 16 年前
        1
  •  4
  •   Ali Ersöz    16 年前

    我想问题出在你的测试方法上。您使用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
  •  2
  •   GeekyMonkey    16 年前

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

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

    当你设定的市场价值为空时会发生什么?最后一行将无效,因为它将无法解析null.mid。也许您的setter需要这个:

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

    而且你的mid必须是空的

    int? MID
    
        3
  •  2
  •   Ali Ersöz    16 年前

    对于您的新问题;该问题发生在对price的selection属性进行空赋值时。你是按密码做的吗?你能再给我一次你发现异常的代码吗?我的意思是分配给价格实体…

    根据评论编辑: 我想这是因为我们之前在geekymonkeys帖子中提到的空控制异常。在选择类的初始化中,price属性需要设置为null,但是当分配给null时,它抛出null引用。所以必须在price属性集合中执行空控件。

    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;
              }
           }
        }
    }
    
        4
  •  2
  •   Neil T.    14 年前

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

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

    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();
    
        5
  •  0
  •   GeekyMonkey    16 年前

    我建议把你的代码发送给西达尔好的。他是个好人,会指引你正确的方向。或者至少在他的博客上发表评论,指出你的问题。