Entity Framework отображает многоуровневые свойства

Я пытаюсь реализовать иерархическую структуру наследования в Entity Framework, специально для настроек. Например, допустим, у нас есть пользовательские настройки:

public class StorePreference: Preference { }

public class UserPreference : Preference { }

public class Preference {
public string BackgroundColor { get; set; }
public ContactMethod ContactMethod { get; set; }
}

public enum ContactMethod {
  SMS,
  Email
}

Мне бы хотелось, чтобы, если я посмотрю настройки пользователя. Если пользователь не существует или значение свойства равно нулю, он ищет настройки родительского (хранилища) по умолчанию.

В идеале мне бы хотелось, чтобы он работал аналогично абстрактному наследованию:

public class UserPreference : StorePreference {
    private string _backgroundColor;

    public string BackgroundColor {
        get { 
           if (this._backgroundColor == null)
              return base;

           return this._backgroundColor;
        } 
        set { this._backgroundColor = value; }
    }
}

Если бы я написал это как SQL-запрос, это был бы CROSS APPLY с оператором CASE:

SELECT 
    CASE WHEN User.BackgroundColor == null THEN Store.BackgroundColor ELSE User.BackgroundColor END BackgroundColor,
    CASE WHEN User.ContactMethod == null THEN Store.ContactMethod ELSE User.ContactMethod END ContactMethod
FROM UserPreference User
CROSS APPLY StorePreference Store
WHERE UserPreference.UserId = @UserId

Есть ли способ, которым я могу добиться загрузки этого в EF?

2 ответа

Пока свойства общедоступны, у объекта не будет проблем с извлечением данных из другой таблицы по умолчанию. Вам нужно будет создать личное поле для хранения данных, если вы используете сеттер:

public class ChildTable : EntityBase {
    private string _someCategory;

    [Key]
    [Column(name: "CHILD_ID")]
    public override int Id { get; protected set; }

    [Column(name: "SOME_CATEGORY")]
    public string SomeCategory {
        get { return _someCategory; }
        set { _someCategory = value ?? ParentTable.SomeCategory; }
    }

    [ForeignKey("ParentTable")]
    [Column(name: "PARENT_ID")]
    public int ParentTableId { get; set; }

    public virtual ParentTable ParentTable { get; set; }
}

Это просто альтернатива конструктору, если вам нужно больше контроля над логикой установщика, иначе ответ Остина будет проще реализовать

В вашем базовом классе добавьте значения свойств по умолчанию:

public class Preference {
    public string BackgroundColor { get; set; } = "Red";
    public ContactMethod ContactMethod { get; set; } = ContactMethod.SMS;
}

Нечто подобное установить из базы данных:

public class StorePreference : Preference { }

public class UserPreference : Preference { }

public class Preference {
    public Preference() {
        BackgroundColor = DefaultPreference.BackgroundColor;
        ContactMethod = DefaultPreference.ContactMethod;
    }

    public string BackgroundColor { get; set; }
    public ContactMethod ContactMethod { get; set; }

    public DefaultPreference DefaultPreference { get; set; }
}

public class DefaultPreference {
    public string BackgroundColor { get; set; }
    public ContactMethod ContactMethod { get; set; }
}
Другие вопросы по тегам