3

Here's what I'm trying to accomplish:

Some entities should be "soft deleted," so I'd like to add a field (and respective column) called "IsDeleted." I'd like this property to be accessible only to the DAL (which can be accomplished via friend assemblies). I'd also like it if the DAL could treat all of these entities the same, via an interface (IDeletable).

To accomplish both goals, I can make IDeletable an internal interface and in classes implementing this interface I can make use of explicit interfaces:

bool IDeletable.IsDeleted { get; set; }

The DAL code would probably look something like this:

public void Delete<T>(T entity)
{
    var d = entity as IDeletable;
    if(d != null)
       //soft delete
       d.IsDeleted = true;
    else
       //hard delete

    //....
 }

The problem is that EF Code First has no way of generating the columns, as far as I can tell. I've tried using expressions, but it complains when I try casting to IDeletable.

Is there a way to force EF Code First to create columns, without expressions?

1
  • Entity Framework supports internal properties. See my answer below. Commented Nov 15, 2013 at 20:15

2 Answers 2

3

First, I would implement the property and add an internal property for EF to know about:

public class A : IDeletable
{
  bool IDeletable.IsDeleted
  {
    get { return this.IsDeleted; }
    set { this.IsDeleted = value; }
  }

  internal bool IsDeleted { get; set; }
}

Second, I would extend DbSet<TEntity>:

public class SmartDbSet<TEntity> : DbSet<TEntity>
{
  public override TEntity Remove(TEntity entity)
  {
    if (entity == null)
      throw //[your favorite exception]

    if (entity is IDeletable)
      (entity as IDeletable).IsDeleted = true;
    else
      base.Remove(entity);

    return entity;
  }
}

Finally your DbContext would look like this:

public class MyDbContext : DbContext
{
  public SmartDbSet<A> As { get; set; }

  protected override void OnModelCreating(DbModelBuilder builder)
  {
    //this is your internal property, NOT the explicit one
    builder.Entity<A>().Property(t => t.IsDeleted);
  }
}

hope this helps

Sign up to request clarification or add additional context in comments.

Comments

-1

I'm not too sure what you mean EF wont create columns without expressions however heres a working example of what you are trying to achieve.

class Program
    {
        static void Main(string[] args)
        {
            using (var ctx = new MyContext())
            {
                var a = new A { IsDeleted = false };
                var b = new B { };
                ctx.As.Add(a);
                ctx.Bs.Add(b);
                ctx.SaveChanges();

                ctx.Delete(a);
                ctx.Delete(b);
            }
            // At this point A is soft deleted and B is permanantly deleted
            Console.ReadLine();
        }
    }



    public class MyContext : DbContext
    {
        public DbSet<A> As { get; set; }
        public DbSet<B> Bs { get; set; }

        public void Delete<T>(T entity) where T:class
        {
            var d = entity as IDeletable;
            if (d != null)
            {
                //soft delete
                d.IsDeleted = true;
            }
            else
            {
                //Use ugly delete as we dont know the dbset this applies to
                this.Entry(entity).State = System.Data.EntityState.Deleted;
            }
            this.SaveChanges();
        }
    }

    public interface IDeletable
    {
        bool IsDeleted { get; set; }
    }

    public class A : IDeletable
    {
        public int Id { get; set; }
        //Implementing this interface adds a column to this entity (no issues here?)
        public bool IsDeleted { get; set; }
    }

    public class B
    {
        public int Id { get; set; }
    }

2 Comments

The problem is that I don't want IsDeleted to be a public property. I want it to be internal to DAL only. So IDeletable is an internal interface and is implemented as explicit. Since EF can't see this property (not because it's internal, but because it's explicit) it's not generating the column.
@GiovanniGalbo There isnt any way of having a private variable exposed to EF, as it needs to be able to read/write to it. The only way to actually do this is by creating a second version of your entities without the deletable property and mapping out of your EF model into another one as you leave you DAL. Obviously this is quite a bit of mucking around. Personally i would just take the hit of having the deletable interface visible rather than going down the mapping path

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.