Наследование свойств данных в EF Core 3.0 - PullRequest
0 голосов
/ 01 ноября 2019

У меня проблема с реализацией иерархии данных в EF Core 3.0 (мне нужно использовать TPH).

Давайте посмотрим:

public abstract class User
{
    public Guid Id { get; set; }
    public string Name { get; set; }

    public abstract UserProfile **Profile** { get; set; }
}

public class ConcreteUser1 : User
{
    public string ConcreteUser1Prop { get; set; }

    public override UserProfile Profile { get; set; }
}

public class ConcreteUser2 : User
{
    public string ConcreteUser2Prop { get; set; }

    public override UserProfile Profile { get; set; }
}

И вот у нас Profileклассы:

public class UserProfile 
{
    public Guid Id { get; set; }

    public string SameProp { get; set; }

    public Guid UserId { get; set; }
    public User User { get; set; }
}

public class ConcreteUser1Profile : Profile
{
    public string ConcreteProfile1Prop { get; set; }
}

public class ConcreteUser2Profile : Profile
{
    public string ConcreteProfile2Prop { get; set; }
}

Пусть это будет только один DbSet<User>, который можно использовать для получения данных из базы данных. Итак, я не могу понять, как сказать EF Core (3.0) 2 вещи: как сказать, чтобы хранить ConcreteUser*Profile (возможно, Add и SaveChanges будет работать правильно и писать конкретный тип профиля, когда я добавляю конкретный типпользователь с конкретным типом профиля, но я не знаю, как сказать EF Core, чтобы получить правильный тип конкретного профиля, когда я использую Where или FirstOrDefault метод? Является ли эта модель правильной в принципе?

UpdНапример, у меня есть две записи в моей базе данных: ConcreteUser1 user1, ConcreteUser2 user2. Итак, давайте получим DbSet<User> Users, так что у меня будет после запроса: var tstUser = ExampleDbContext.Users.FirstOrDefault();? Что будет тип переменной Profile вtstUser.Profile

Ответы [ 2 ]

1 голос
/ 01 ноября 2019

Вы можете использовать HasDiscriminator при создании модели.

Он будет использовать поле, чтобы определить, к какому конкретному пользовательскому классу вы пытаетесь сопоставить данные.

Для васэто будет что-то вроде:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<User>()
        .HasDiscriminator<int>("UserType")
        .HasValue<ConcreteUser1>(1)
        .HasValue<ConcreteUser2>(2);
}

Больше на: https://www.learnentityframeworkcore.com/configuration/fluent-api/hasdiscriminator-method

0 голосов
/ 09 ноября 2019

У меня есть решение (возможно, кто-то тоже будет его использовать).

public class UserProfile 
{
    public Guid Id { get; set; }

    public ProfileRoles Role { get; set;}

    public string SameProp { get; set; }

    public Guid UserId { get; set; }
    public User User { get; set; }
}

public class ConcreteUser1Profile : UserProfile
{
    public string ConcreteProfile1Prop { get; set; }
}

public class ConcreteUser2Profile : UserProfile
{
    public string ConcreteProfile2Prop { get; set; }
}

и

public class User
{
    public Guid Id { get; set; }
    public string Name { get; set; }

    public UserRoles Role { get; set; }

    public UserProfile Profile { get; set; }
}

public class ConcreteUser1 : User
{
    public string ConcreteUser1Prop { get; set; }
}

public class ConcreteUser2 : User
{
    public string ConcreteUser2Prop { get; set; }
}

public enum UserRoles
{
    User = 0,
    ConcreteUser1 = 1,
    ConcreteUser2 = 2 
}

public enum ProfileRoles
{
    BaseProfile = 0,
    ConcreteProfile1 = 1,
    ConcreteProfile2 = 2
}

И оно должно быть хорошо настроено в DbContext:

public class UserStoreDbContext : DbContext
{
    DbSet<User> Users { get; set; }
    DbSet<UserProfile> Profiles { get; set; }

    public UserStoreDbContext(DbContextOptions<UserStoreDbContext> options) : base(options) { }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<User>(builder =>
            {
                builder.HasDiscriminator<UserRoles>(x => x.Role)
                       .HasValue<User>(Roles.User)
                       .HasValue<Logistian>(Roles.ConcreteUser1)
                       .HasValue<Driver>(Roles.ConcreteUser2)
            });

            modelBuilder.Entity<UserProfile>(builder =>
            {
                builder.HasDiscriminator<ProfileRoles>(x => x.Role)
                       .HasValue<UserProfile>(ProfileRoles.BaseProfile)
                       .HasValue<ConcreteUser1Profile>(Roles.ConcreteProfile1)
                       .HasValue<ConcreteUser2Profile>(Roles.ConcreteProfile2)
            });
    }
}

В этом случае, когда вы будете использовать код, такой как: dbContext.Users.FirstOrDefault(), вы также получите правильный производный профиль от UserProfile.

Возможно, кому-то тоже понадобится это решение.

...