Entity Framework 4 TPH inheritance, how to change one type into another?

前端 未结 4 1083
执笔经年
执笔经年 2020-12-11 19:43

I have found some information regarding this but not enough for me to understand what the best practice for is for this scenario. I have your typicaly TPH setup with an abs

4条回答
  •  庸人自扰
    2020-12-11 20:01

    EDIT: APOLOGIES, THIS IS AN EF 6.x ANSWER

    I'm posting example code for completeness. In this scenario, I have a base Thing class. Then, sub-classes: ActiveThing and DeletedThing

    My OData ThingsController, has a main GetThings which I intend to only expose ActiveThings, but, it's GetThing(ThingId) can still return either type of object. The Delete action performs a conversion from ActiveThing to DeletedThing much in the way requested by the OP, and much in the manner described in other answers. I'm using inline SQL (parameterized)

    public class myDbModel:DbContext
    {
        public myDbModel(): base("name=ThingDb"){}
    
        public DbSet Things { get; set; }  //db table
    
        public DbSet ActiveThings { get; set; } // now my ThingsController 'GetThings' pulls from this
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
           //TPH (table-per-hierarchy):
          modelBuilder.Entity()
            .Map(thg => thg.Requires("Discriminator").HasValue("A"))
            .Map(thg => thg.Requires("Discriminator").HasValue("D"));
        }
    
    }
    

    Here's my updated ThingsController.cs

    public class ThingsController : ODataController
    {
        private myDbModel db = new myDbModel();
    
        /// 
        /// Only exposes ActiveThings (not DeletedThings)
        /// 
        /// 
        [EnableQuery]
        public IQueryable GetThings()
        {
            return db.ActiveThings;
        }
    
        public async Task Delete([FromODataUri] long key)
        {
            using (var context = new myDbModel())
            {
                using (var transaction = context.Database.BeginTransaction())
                {
                    Thing thing = await db.Things.FindAsync(key);
                    if (thing == null || thing is DeletedThing) // love the simple expressiveness here
                    {
                        return NotFound();//was already deleted previously, so return NotFound status code
                    }
    
                    //soft delete: converts ActiveThing to DeletedThing via direct query to DB
                    context.Database.ExecuteSqlCommand(
                        "UPDATE Things SET Discriminator='D', DeletedOn=@NowDate WHERE Id=@ThingId", 
                        new SqlParameter("@ThingId", key), 
                        new SqlParameter("@NowDate", DateTimeOffset.Now)
                        );
    
                    context.ThingTransactionHistory.Add(new Ross.Biz.ThingStatusLocation.ThingTransactionHistory
                    {
                        ThingId = thing.Id,
                        TransactionTime = DateTimeOffset.Now,
                        TransactionCode = "DEL",
                        UpdateUser = User.Identity.Name,
                        UpdateValue = "MARKED DELETED"
                    });
                    context.SaveChanges();
                    transaction.Commit();
                }
            }
    
            return StatusCode(HttpStatusCode.NoContent);
        }
    }
    

提交回复
热议问题