views:

43

answers:

1

I have a problem with some simple code, I'm refactoring some existing code from LINQ to SQL to the Entity Framework. I'm testing my saves and deletes, and the delete is really bugging me:

[TestMethod]
public void TestSaveDelete()
{
    ObjectFactory.Initialize(x =>
    {
        x.For<IArticleCommentRepository>().Use<ArticleCommentRepository>();
    });

    PLArticleComment plac = new PLArticleComment();
    plac.Created = DateTime.Now;
    plac.Email = "myemail";
    plac.Name = "myName";
    plac.Text = "myText";
    plac.Title = "myTitle";

    IArticleCommentRepository acrep = ObjectFactory.GetInstance<IArticleCommentRepository>();
    try
    {
        PortalLandEntities ple = new PortalLandEntities();
        int count = ple.PLArticleComment.Count();
        acrep.Save(plac);
        Assert.AreEqual(ple.PLArticleComment.Count(), count + 1);
        //PLArticleComment newPlac = ple.PLArticleComment.First(m => m.Id == plac.Id);
        //ple.Attach(newPlac);
        acrep.Delete(plac);
        Assert.AreEqual(ple.PLArticleComment.Count(), count + 1);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}

Every time i try to run this code, I get an exception in the delete statement, telling me that its not contained within the current ObjectStateManager.Please note that both my Save and delete looks like this:

public void Delete(PLCore.Model.PLArticleComment comment)
{
    using (PortalLandEntities ple = Connection.GetEntityConnection())
    {
        ple.DeleteObject(comment);
        ple.SaveChanges();
    }
}

public void Save(PLCore.Model.PLArticleComment comment)
{
    using (PortalLandEntities ple = Connection.GetEntityConnection())
    {
        ple.AddToPLArticleComment(comment);
        ple.SaveChanges();
    }
}

and the connection thingy:

public class Connection
{
    public static PortalLandEntities GetEntityConnection()
    {
        return new PortalLandEntities();
    }
}

Any ideas on what i could do to make it work?

+1  A: 

You cannot load an entity from one ObjectContext (in your case, an ObjectContext is an instance of PortalLandEntities) and then delete it from another ObjectContext, unless you detach it from the first and attach it to the second. Your life will be much, much simpler if you use only one ObjectContext at a time. If you cannot do that, you must manually Detach and then Attach first, all the while keeping track of which entities are connected to which ObjectContext.

How to use DI with your Connection : make it non-static.

public class Connection
{
    private PortalLandEntities _entities;

    public PortalLandEntities GetEntityConnection()
    {
        return _entities;
    }

    public Connection(PortalLandEntities entities)
    {
        this._entities = entities;
    }
}

Then use a DI container per request. Most people do this via a controller factory.

Craig Stuntz
How would i then implement a new version of my "Connection" class? I like the structure it has now, since i can change the database only one place and overload the getConnection if necessary... should i do a singleton?
H4mm3rHead
Use DI to inject a single `ObjectContext` instance per request instead of newing one up internally. Note that this also makes your class more testable.
Craig Stuntz
Ok, Think you lost me. How would I go about doing this DI? Could you please write the method signature? How do I solve my "Save" and "Delete" then, should they take the ObjectContect as parameter? (I would really hate that, would like to keep it invisible from the client). Please note that im using StructureMap as my IOC.
H4mm3rHead
I added an example.
Craig Stuntz
Thank you very much! This would equal having a private instance variable of type PortalLandentities on everyone of my Repository classes, right? Then if i want to run on a different database (using the overloaded constructor of the ObjectContext, which takes a connectionstring as parameter) - i would still have to change all my repositories to use the same connectionstring?In your example, then how would i instantiate the "Connection" class the first time (im asuming that it only happens once?)
H4mm3rHead
We use an instance variable in repositories. It's not the only way, but it works. Repositories don't know about connection strings, because they don't new up the context; they get an instance on construction. Your DI container would instantiate `Connection`.
Craig Stuntz
thanks for all your help, really appreciate it.
H4mm3rHead