【问题标题】:Entity Framework - how to seed test data to entities that use table-per-type inheritance?实体框架 - 如何将测试数据播种到使用每类型表继承的实体?
【发布时间】:2013-01-18 09:42:40
【问题描述】:

我使用的是 EF5 代码优先、迁移和每个类型的表继承。我有一些从其他类继承的类。例如TenantLandlord 继承自UserProfile

我正在使用protected override void Seed() 方法将测试数据添加到我的数据库中。因此,例如,我创建了 2 个UserProfile 对象和 1 个Tenant 和 1 个Landlord。如何确保租户实体与第一个用户配置文件实体相关联,而房东实体与第二个用户配置文件实体相关联?因为我使用的是 table-per-type 继承,我是否需要明确说明派生类的 UserId 等于其基类的 UserId?我四处寻找,但找不到任何有用的东西。我尝试按如下方式进行:

protected override void Seed(Context context)
    {
        var users = new List<UserProfile>
        {
             new UserProfile { UserId=1, UserName="Matt", Email="a@a.com", AccountType=AccountType.Tenant },
             new UserProfile { UserId=2, UserName="Dave", Email="a@a.com", AccountType=AccountType.Landlord }
        };
        users.ForEach(u => context.UserProfile.AddOrUpdate(u));
        context.SaveChanges();

        var tenants = new List<Tenant>
        {
            new Tenant { UserId = users.Single(x => x.UserId = 1) /* other properties */  }
            // ...
        };
        tenants.ForEach(t => context.Tenant.AddOrUpdate(t));
        context.SaveChanges();

        var landlords = new List<Landlord>
        {
            new Landlord { UserId = users.Single(x => x.UserId = 2) /* other properties */ }
            // ...
        };
        landlords.ForEach(l => context.Tenant.AddOrUpdate(l));
        context.SaveChanges();
    }

【问题讨论】:

  • 如果“Matt”是Tenant,您必须将其创建为Tenant,而不是UserProfile。这就是继承的全部意义。

标签: c# entity-framework inheritance table-per-type seeding


【解决方案1】:

您必须使用 DbContext 来加载要分配给它的实体。

应该这样做:

protected override void Seed(Context context)
    {
        var users = new List<UserProfile>
    {
         new UserProfile { UserId=1, UserName="Matt", Email="a@a.com", AccountType=AccountType.Tenant },
         new UserProfile { UserId=2, UserName="Dave", Email="a@a.com", AccountType=AccountType.Landlord }
    };
        users.ForEach(u => context.UserProfile.AddOrUpdate(u));
        context.SaveChanges();

        var tenants = new List<Tenant>
    {
        new Tenant { UserId = users.Single(x => x.UserId = context.UserProfile.First(x=>x.UserId = 1)) /* other properties */  }
        // ...
    };
        tenants.ForEach(t => context.Tenant.AddOrUpdate(t));
        context.SaveChanges();

        var landlords = new List<Landlord>
    {
        new Landlord { UserId = users.Single(x => x.UserId = context.UserProfile.First(x=>x.UserId = 2)) /* other properties */ }
        // ...
    };
        landlords.ForEach(l => context.Tenant.AddOrUpdate(l));
        context.SaveChanges();
    }

【讨论】:

    【解决方案2】:

    虽然 Maximc 的想法是正确的,但我发现您可以使用 DbContext.Set&lt;T&gt; 方法为您的子类使用 AddOrUpdate 方法,而无需先手动从数据库中获取它们:

    protected override void Seed(Context context)
    {            
        context.Set<Tenant>().AddOrUpdate(
            t => t.UserName, // or whatever property you want to use as an identifier for duplicates
            new Tenant { UserId=1, UserName="Matt", Email="a@a.com" });
    
        context.Set<Landlord>().AddOrUpdate(
            t => t.UserName,
            new Tenant { UserId=2, UserName="Dave", Email="a@a.com" });
    }
    

    另外,您可能不应该自己指定鉴别器(在您的情况下为 AccountType)。当您正确设置 POCO 继承时,Entity Framework 将在后台为您处理。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多