views:

28

answers:

1

I am trying to implement an UnitOfWork type pattern where one DataContext is used over a short group of related methods and only at the end do I save the changes. However, I have found that entities added to the ObjectContext do seem to be available for reselection unless I SaveChanges, which is what I am trying to avoid. Can someone tell me if this is the expected behaviour? I have provided a psuedo test to illustrate:

    [Test]
    public void ObjectContext_ShouldSelectBackUncommitedValuesWhenUsingTheSameContext()
    {
        //arrange
        var entityConnectionString = "MyEntityConnectionString";
        var dataContext = new MyObjectContext(entityConnectionString);

        var personCount = dataContext.People.AsQueryable<Person>().Count();
        var person = new Person() { Name = "Bob" };

        //act
        dataContext.AddToPeople(person);

        //assert
        var actualPerson = dataContext.People.AsQueryable<Person>().Where(p => p.Name == "Bob").FirstOrDefault();
        Assert.IsTrue(actualPerson != null,"Uncommitted Person should return when using same context");

        var actualCount = dataContext.People.AsQueryable<Person>().Count();
        Assert.IsTrue(actualCount == personCount + 1, String.Format("Expected {0} people but got {1} people", personCount + 1, actualCount));

        //leave transaction to rollback

    }

This test fails with the actualPerson being null and the Count of the People set not incrementing. Forgive me if there are any typos as I have just simplified my own ObjectContext.

FYI I am using EF 4.

TIA.

--EDIT-- Further by way of analogy, I was hoping to be able to work with uncommitted objects as I can in SQL eg:

CREATE TABLE Person (Name nvarchar(10));
INSERT INTO Person VALUES ('Francois')
INSERT INTO Person VALUES ('Hans')

SELECT COUNT(*) FROM Person

BEGIN TRANSACTION
INSERT INTO Person VALUES ('Bob')
SELECT 'Bob Lives!' WHERE EXISTS(SELECT * FROM Person WHERE NAME='Bob')
ROLLBACK TRANSACTION

DROP TABLE Person
A: 

Doing this

dataContext.People.AsQueryable<Person>().Where(p => p.Name == "Bob").FirstOrDefault();

actually results in a database call, so it shouldn't return any unpersisted data. If you want to get your person back, you have to use ObjectStateManager:

dataContext.ObjectStateManager.
           GetObjectStateEntries(EntityState.Added | EntityState.Deleted | 
                                 EntityState.Modified | EntityState.Unchanged).
           Where(ent => ent.Entity is Person).
           Select(ent => ent.Entity as Person).
           Where(p => p.Name == "Bob").
           FirstOrDefault();
Yakimych
Thanks Yakimych, I understand I can do this, but what I was looking to find out is whether, using my ObjectContext as a 'Unit of Work', I can or should be able to access all objects within the scope of the ObjectContext without always having to do a union of the ObjectQuery results and the ObjectStateManager results. I have added and analogy using SQL as to what I was hoping to achieve.
Simon Francesco
As I mentioned in the post, trying to access a query via `objectContext.Person` will result in a DB query, so basically it will reflect the data in your DB at the moment. One can argue whether it's a good or bad implementation, but that's how it is implemented. As a result (answering your question), you cannot access any unpersisted objects/changes without using `ObjectStateManager`.This issue has been up for debate, btw. Check out this topic for clarifications: http://stackoverflow.com/questions/3118769/is-entity-framework-objectcontext-correct-implementation-of-unit-of-work-pattern
Yakimych
Thanks Yakimych.For what it is worth, I hope MS change this implementation as I don't want to have 2 ways to access objects, it means the next layer up has to know too much about the way objects are stored.Also I don't even really want to know whether the Where method makes a DB call, I don't even want to know there is a db.It would be much more intuitive if the ObjectSet reflected all the unpersisted changes. Surely this is what the "Context" in DataContext should stand for otherwise the object should be called a DataOutOfContext object :)
Simon Francesco