'Sequence contains more than one element' (InvalidOperationException) thrown by external System.Core call when using Linq2Sql

StackOverflow https://stackoverflow.com/questions/16464404

Question

firstly let me explain that I fully understand why this InvalidOperationException has been thrown and that I am simply looking for a way to avoid it from being thrown. There is a call to System.Linq.Enumerable.SingleOrDefault() that I can see in the Visual Studio 2010 Call Stack window. However, the call is in external Linq2Sql code, so I have no access to change it.

Call Stack showing (mostly) external code. (Sorry, you may need to zoom in to see this image properly)

The last internal code call before execution goes external is found in the application dbml.designer.cs file which I do have access to, but still cannot edit because it updates automatically and loses custom changes. It is in a (Linq2Sql) property setter for one of the database tables used in the application and it appears that the problem is caused by the call to the _DbAudioTrackContributors.Entity object:

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");
        }
    }
}

If anyone has a way to provide me with the internal code for the EntityRef<TEntity> struct (or even just the Entity property), this could possibly help me to work out what is causing the problem.

The last line of my own code before the InvalidOperationException is thrown is a call to 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;
        }
    }
}

The CopyToDbAudioTrack method simply copies all of the property values from the AudioTrack object to the Linq2Sql generated DbAudioTrack object and the UpdateAudioTrackContributors method is shown below.

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);
}

This method simply finds the Label objects that have changed and either adds or deletes them in the AudioTrackContributors database table. This table seems to be the root of the problem as it disappears if this code is commented out. However, this method correctly selects the objects to add or delete, so I am still confused. The AddAudioTrackContributors method basically calls the code shown below and the DeleteAudioTrackContributors code is shown below that:

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);

Again, stepping through the code during execution shows that the above code also correctly selects the right objects to delete. As I can't see any problems in my code, I don't know where to look next.

If anyone has any ideas on how to proceed, I would be very glad to hear them. Many thanks in advance.

Was it helpful?

Solution

Ok, so this was a hideous problem with no clear clues as to the actual cause. It turned out to be the definition of the DbAudioTrackContributor table in the Linq2Sql dbml file.

Luckily, I also had a DbMasterTrackContributor table which did not suffer from the same error. After comparing all of my code that related to the two tables and this update, I could find no differences. Then, I decided to look at the Linq2Sql generated designer code and noticed a difference between the two table definitions.

The DbAudioTrackContributor table was registered as an EntityRef<DbAudioTrackContributor> whereas the working DbMasterTrackContributor table was registered as an EntitySet<DbMasterTrackContributor>.

After looking online at the differences between them, it turned out that EntityRef<T> is used for one to one relationships and EntitySet<T> is used for one to many and many to many relationships. I therefore suspected that they should both have been declared as EntitySet<T>, so I deleted the table from the dbml file and then re-added it.

After doing this, it began to work again! So I learnt a valuable lesson: If I have a dbml related error, first try removing and re-adding the suspect table(s) from the dbml file.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top