Entity Framework - как заполнить тестовые данные объектами, которые используют наследование таблиц для типов?

Я использую код EF5, миграцию и наследование таблиц. У меня есть некоторые классы, которые наследуются от других классов. Например Tenant а также Landlord наследовать от UserProfile,

Я использую protected override void Seed() способ добавить данные испытаний в мою базу данных. Так, например, я создаю 2 UserProfile объекты и 1 Tenant и 1 Landlord, Как убедиться, что объект-арендатор связан с первым объектом профиля пользователя, а объект арендодателя связан со вторым объектом профиля пользователя? Поскольку я использую наследование таблиц для каждого типа, мне нужно явно сказать, что 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();
    }

2 ответа

Вы должны использовать 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();
    }

Хотя у Maximc правильная идея, я обнаружил, что вы можете использовать DbContext.Set<T> метод, чтобы использовать 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) самостоятельно. Entity Framework будет обрабатывать это для вас в фоновом режиме, когда вы правильно настроите наследование POCO.

Другие вопросы по тегам