views:

38

answers:

1

Hi,

I'm working with a small model in Entity Framework 4.0. I'd like to have an instance method of the object that represents an entity persist the entity to the database. So instead of from "external" code:

public static void Main(string[] args)
{
   using (EFContext ctx = new EFContext())
   {
       context.AnEntitySet.AddObject(refToTheEntityInstance);
       context.SaveChanges();

Instead, I want the instance of the entity to persist itself, where Contact is the entity name.

public ContactInstance : Contact
{
    public void Persist(List<AnotherEntity> otherEntityList)
    {
        using (EFContext ctx = new EFContext())
        {
            ...
            ctx.Contacts.AddObject(this); // DOESN'T WORK.
            ...
            ...wire up navigation property to collection of AnotherEntity...
            ctx.SaveChanges();

I'm doing something wrong. Is this a bad design ? It seems to me that an entity, like any object in object oriented design, should "know" how to persist itseld.

Thabks,

Scott

+1  A: 

From a patterns perspective you are trying to introduce the ActiveRecord pattern, which some people love, some people hate. So asking if this is bad design might turn religious very quickly :)

Having said that it is a common pattern, unfortunately it is not natively supported by the EF.

There are a number of problems with your code:

1) ContactInstance can't be treated as a Contact, which is what you appear to be trying to do, in EF, if you have a derived type in the CLR (i.e. ContactInstance) it must correspond to a derived type in the Entity Model too. (i.e. an Entity type called ContactInstance) which I suspect you don't have. I'm guess you have this just to add the Persist method. Another way to do that is in a partial class (EF works fine with partial classes:

public partial class Contact
{
    public void Persist(...){}
}

2) Next your code has some issues with Entities potentially being attached to multiple ObjectContexts, for example if you write this code:

Contact c = new Contact();
c.Firstname = ...;
c.Surname = ...;
c.Persist();
c.Surname = ...;
c.Persist();

It will fail - in the second call to Persist() - because an Entity can only be attached to one Context at a time:

  • The first Persist(). adds the entity to one context.
  • And the second Persist() will attempt to add the same entity to another context. Exception time!.

The workaround for this is to have an Ambient context somehow, using something like ThreadBound statics or something, but then you have to deal with all sorts of tricky issues.

Anyway the moral of the story is that what you are trying is possible using EF, but it isn't easy, you have to really think through things like ObjectContext lifetime, issues like attach / detach etc.

Hope this helps

Alex James

Former EF team member

Alex James