Search code examples
c#linq-to-sqlexceptiondatacontext

Linq2SQL, use dataContext after Exception


Here a small piece of code for testing and explain the problem. I have a table Person with 3 fields :

  • Id
  • FirstName (not nullable)
  • LastName (not nullable)

In the loop :

  • First : I insert the first row ... normal,
  • Second : I try to insert a not correct item, Exception ... normal
  • Third : I try to insert the third row ... Exception (same than for the second) but the values are correct.

Is there something to do to use the same dataContext after an Exception ?

public class MyTestClass
{
    private readonly DataModelDataContext _dataContext;

    public MyTestClass()
    {
        _dataContext = new DataModelDataContext();
    }

    public void InsertList()
    {
        List<Person> liste = new List<Person>();
        liste.Add(new Person { FirstName = "AAA", LastName = "BBBB" });
        liste.Add(new Person { FirstName = string.Empty, LastName = null });
        liste.Add(new Person { FirstName = "CCC", LastName = "DDD" });

        foreach (var item in liste)
        {
            try
            {
                _dataContext.Persons.InsertOnSubmit(item);
                _dataContext.SubmitChanges();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}

Solution

  • The DataContext should always be short-lived. You should re-factor your design to achieve this.

    You can consider these points:

    • Use context per transaction. This way you can make the context short-lived in meaningful way.
    • Rollback when your transaction fails. This includes inserting correct item with new transaction. That means, you have a fresh different context now.
    • Repeat the process until the transaction completes.
    • Again, don't forget to end the context when you are done. This can be easily achieved by making use of the using statement.

    Remark from MSDN:

    The DataContext is the source of all entities mapped over a database connection. It tracks changes that you made to all retrieved entities and maintains an "identity cache" that guarantees that entities retrieved more than one time are represented by using the same object instance.

    In general, a DataContext instance is designed to last for one "unit of work" however your application defines that term. A DataContext is lightweight and is not expensive to create. A typical LINQ to SQL application creates DataContext instances at method scope or as a member of short-lived classes that represent a logical set of related database operations.


    If it takes time to re-factor your design, temporarily you can do like this:

        public void InsertList(List<Person> people)
        {
            foreach (var person in people)
            {
                DoInsert(person); 
                // You can use the returned flag and implement the logic if desired.
                // Or let the loop move on its ways.
            }
        }
    
        public bool DoInsert(Person person)
        {
            try
            {
                using (DataModelDataContext dataContext = new DataModelDataContext())
                {
                    dataContext.Persons.InsertOnSubmit(person);
                    dataContext.SubmitChanges();
                }
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return false;
            }
        }
    

    and this is how you can call InserList Method:

        List<Person> liste = new List<Person>();
        liste.Add(new Person { FirstName = "AAA", LastName = "BBBB" });
        liste.Add(new Person { FirstName = string.Empty, LastName = null });
        liste.Add(new Person { FirstName = "CCC", LastName = "DDD" });
    
        InsertList(liste);