代码之家  ›  专栏  ›  技术社区  ›  e36M3

实体框架4tph继承,如何将一种类型转换成另一种类型?

  •  5
  • e36M3  · 技术社区  · 15 年前

    1. 不要使用TPH。只要有一个公司实体,然后返回到using.Where(FirmTypeId==something)来区分这些类型。
    2. 直接使用context.ExecuteStoreCommand执行SQL以更新数据库的FirmTypeId列。

    我看过一篇文章,人们建议OOP的原则之一是实例不能改变它们的类型。尽管这对我来说很有意义,但我似乎无法把这些点联系起来。如果我们要遵循这个规则,那么使用任何类型的继承(TPH/TPT)的唯一时间是当一个类型确信一个类型永远不会转换为另一个类型时。所以小公司永远不会变成大公司。我看到有人建议用作文代替。即使这对我来说没有意义(也就是说我看不出一家公司是如何拥有一家大公司的,对我来说,一家大公司就是一家公司),但我可以看到,如果数据在多个表中,那么如何在EF中对组成进行建模。然而,在数据库中只有一个表的情况下,它似乎是TPH或者我在上面的1和2中描述的。

    4 回复  |  直到 15 年前
        1
  •  2
  •   Community Mohan Dere    8 年前

    我在我们的项目中遇到了这个问题 DBContext DBContexts ,其中“模块用户”继承“核心(基本)用户”。希望这是可以理解的。

    我们也需要改变的能力 User Customer Users 同时,让用户可以使用所有这些模块。

    因此,我们尝试使用TPT继承,而不是TPH—但是TPH也会以某种方式工作。

    一种方法是 正如许多人所建议的。。。

    我想到的另一个办法是 自定义插入/更新查询 到数据库。在 TPT公司 可能是:

    private static bool UserToCustomer(User u, Customer c)
        {
            try
            {
                string sqlcommand = "INSERT INTO [dbo].[Customers] ([Id], [Email]) VALUES (" + u.Id + ", '" + c.Email + "')";
                var sqlconn = new SqlConnection(ConfigurationManager.ConnectionStrings["DBContext"].ConnectionString);
                sqlconn.Open();
                var sql = new SqlCommand(sqlcommand, sqlconn);
                var rows = sql.ExecuteNonQuery();
                sqlconn.Close();
    
                return rows == 1;
            }
            catch (Exception)
            {
                return false;
            }
        }
    

    顾客 用户 只有 string Email .

    使用时 TPH公司 INSERT ... VALUES ... UPDATE ... SET ... WHERE [Id] = ... . 别忘了换衣服 Discriminator 专栏也是。

    下次通话后 dbcontext.Users.OfType<Customer> 有我们的原始用户,“转换”为客户。


    底线:我还尝试了另一个问题的解决方案,其中包括 分离 ObjectStateManager 使新的实体(客户)状态 被改进的 ,然后保存 dbcontext.SaveChanges() It can be found here.

        2
  •  1
  •   Community Mohan Dere    8 年前

    是的,你没事。EF继承不支持此方案。改变一个 坚定的 为现有的 坚定的 使用存储过程。


    Changing Inherited Types in Entity Framework

        3
  •  0
  •   Slappy    15 年前

    除非您明确地想要使用关系继承的多态功能,否则为什么不看看拆分策略呢?

    http://msdn.microsoft.com/en-us/data/ff657841.aspx

        4
  •  0
  •   bkwdesign    9 年前

    编辑:抱歉,这是EF6.x的答案

    为了完整起见,我发布了示例代码。在这种情况下,我有一个基地 Thing 上课。然后,子类: ActiveThing DeletedThing

    我的奥达塔 ThingsController ,有一个主 GetThings 活性物质 s、 但是,getting(ThingId)仍然可以返回任何类型的对象。这个 Delete 活性物质 很多是操作人员要求的方式,很多是其他答案中描述的方式。我正在使用内联SQL(参数化)

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

    这是我的最新消息controller.cs

    public class ThingsController : ODataController
    {
        private myDbModel db = new myDbModel();
    
        /// <summary>
        /// Only exposes ActiveThings (not DeletedThings)
        /// </summary>
        /// <returns></returns>
        [EnableQuery]
        public IQueryable<Thing> GetThings()
        {
            return db.ActiveThings;
        }
    
        public async Task<IHttpActionResult> 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);
        }
    }