0

首先让我解释一下,我完全理解为什么InvalidOperationException会抛出这个,我只是在寻找一种方法来避免它被抛出。System.Linq.Enumerable.SingleOrDefault()我可以在 Visual Studio 2010 调用堆栈窗口中看到一个调用。但是,调用是在外部Linq2Sql代码中,所以我无权更改它。

显示(大部分)外部代码的调用堆栈。 (抱歉,您可能需要放大才能正确查看此图像)

在我有权访问的应用程序文件中找到执行外部之前的最后一次内部代码调用dbml.designer.cs,但仍然无法编辑,因为它会自动更新并丢失自定义更改。它位于Linq2Sql应用程序中使用的其中一个数据库表的 () 属性设置器中,看起来问题是由对_DbAudioTrackContributors.Entity对象的调用引起的:

public DbAudioTrackContributor DbAudioTrackContributors
{
    get
    {
        return this._DbAudioTrackContributors.Entity;
    }
    set
    {
        // This is the last internal line before the Exception 
        DbAudioTrackContributor previousValue = this._DbAudioTrackContributors.Entity;

        // Execution never reaches here
        if (((previousValue != value) || 
        (this._DbAudioTrackContributors.HasLoadedOrAssignedValue == false)))
        {
            this.SendPropertyChanging();
            if ((previousValue != null))
            {
                this._DbAudioTrackContributors.Entity = null;
                previousValue.DbAudioTrack = null;
            }
            this._DbAudioTrackContributors.Entity = value;
            if ((value != null))
            {
                value.DbAudioTrack = this;
            }
            this.SendPropertyChanged("DbAudioTrackContributors");
        }
    }
}

如果有人有办法向我提供EntityRef<TEntity>结构(甚至只是Entity属性)的内部代码,这可能会帮助我找出导致问题的原因。

在抛出之前我自己的代码的最后一行InvalidOperationException是调用dataContext.SubmitChanges()

public int UpdateAudioTrack(AudioTrack audioTrack)
{
    using (TransactionScope transactionScope = new TransactionScope())
    {
        using (MidasDataContext dataContext = DataContext)
        {
            DbAudioTrack dbAudioTrack = dataContext.DbAudioTracks.Where(
                g => g.Id == audioTrack.Id).FirstOrDefault();
            if (dbAudioTrack == null) return -1;
            CopyToDbAudioTrack(audioTrack, dbAudioTrack);
            UpdateAudioTrackContributors(dataContext, audioTrack);

            // This is the last line of my code before the Exception 
            dataContext.SubmitChanges(ConflictMode.FailOnFirstConflict);

            // Execution never reaches here
            transactionScope.Complete();
            return 0;
        }
    }
}

CopyToDbAudioTrack方法只是将对象中的所有属性值复制AudioTrackLinq2Sql生成的DbAudioTrack对象中,该UpdateAudioTrackContributors方法如下所示。

private void UpdateAudioTrackContributors(MidasDataContext dataContext, AudioTrack audioTrack)
{
    DataList<Label> labels = new DataList<Label>(
        audioTrack.Labels.Except(audioTrack.OriginalState.Labels));
    if (labels.Count > 0) AddAudioTrackContributors(dataContext, audioTrack, labels);
    labels = new DataList<Label>(audioTrack.OriginalState.Labels.Except(audioTrack.Labels));
    if (labels.Count > 0) DeleteAudioTrackContributors(dataContext, audioTrack, labels);
}

此方法只是查找已更改的对象,然后在数据库表Label中添加或删除它们。AudioTrackContributors该表似乎是问题的根源,因为如果注释掉此代码,它就会消失。但是,这种方法正确地选择了要添加或删除的对象,所以我仍然感到困惑。该AddAudioTrackContributors方法基本上调用如下所示的代码,DeleteAudioTrackContributors代码如下所示:

List<DbAudioTrackContributor> dbAudioTrackContributors = new List<DbAudioTrackContributor>();
foreach (T dataListEntry in dataList)
{
    DbAudioTrackContributor dbAudioTrackContributor = new DbAudioTrackContributor();
    CopyToDbAudioTrackContributor(audioTrack, dataListEntry, dbAudioTrackContributor, contributorType);
    dbAudioTrackContributors.Add(dbAudioTrackContributor);
}
dataContext.DbAudioTrackContributors.InsertAllOnSubmit(dbAudioTrackContributors);

DeleteAudioTrackContributors

List<DbAudioTrackContributor> dbAudioTrackContributors = new List<DbAudioTrackContributor>();
foreach (T dataListEntry in dataList)
{
    DbAudioTrackContributor dbAudioTrackContributor = dataContext.DbAudioTrackContributors.Where(d => d.DataListId == dataListEntry.Id && d.AudioTrackId == audioTrack.Id).FirstOrDefault();
    if (dbAudioTrackContributor != null) dbAudioTrackContributors.Add(dbAudioTrackContributor);
}
dataContext.DbAudioTrackContributors.DeleteAllOnSubmit(dbAudioTrackContributors);

同样,在执行期间单步执行代码表明上述代码也正确选择了要删除的正确对象。由于我在我的代码中看不到任何问题,因此我不知道下一步该往哪里看。

如果有人对如何进行有任何想法,我会很高兴听到他们的声音。提前谢谢了。

4

1 回答 1

2

好的,所以这是一个可怕的问题,没有关于实际原因的明确线索。原来是dbml文件DbAudioTrackContributor中表的定义。Linq2Sql

幸运的是,我还有一张DbMasterTrackContributor没有出现同样错误的表。在比较了与这两个表和此更新相关的所有代码后,我没有发现任何差异。然后,我决定查看Linq2Sql生成的设计器代码,并注意到两个表定义之间的差异。

DbAudioTrackContributor表被注册为 ,EntityRef<DbAudioTrackContributor>而工作DbMasterTrackContributor表被注册为EntitySet<DbMasterTrackContributor>

网上看了下它们之间的区别,原来EntityRef<T>是用于一对一的关系,EntitySet<T>用于一对多和多对多的关系。因此,我怀疑它们都应该被声明为EntitySet<T>,所以我从 dbml 文件中删除了该表,然后重新添加了它。

这样做之后,它又开始工作了!所以我学到了宝贵的一课:如果我有一个与 dbml 相关的错误,首先尝试从 dbml 文件中删除并重新添加可疑表。

于 2013-05-10T11:50:48.657 回答