【问题标题】:Entity Framework map multiple level properties实体框架映射多级属性
【发布时间】:2017-04-17 20:17:14
【问题描述】:

我正在尝试在实体框架中实现分层继承结构,专门用于设置。例如,假设我们有用户偏好:

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
}

如果我查找用户的偏好,我会喜欢它。如果用户不存在或属性值为 null,则查找父(存储)默认首选项。

理想情况下,我希望它类似于抽象继承:

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 查询,它将是一个带有 CASE 语句的 CROSS APPLY:

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 中加载它?

【问题讨论】:

    标签: c# entity-framework cross-apply


    【解决方案1】:

    在您的基类中添加默认属性值:

    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; }
    }
    

    【讨论】:

    • 这硬编码默认值。我希望它们在数据库中,以便可以更改默认值
    • 你可以让 Preference 默认它自己的对象,比如DefaultPreference,然后在构造函数中设置默认值吗?
    • 我刚刚更新了答案以反映一个 DefaultPreference 对象,如果您希望它与数据库分开,则该对象必须分开。
    • 这将使 UserPreference 使用来自 Preference 的值而不是 StorePreference 如果它为 null 并且如果用户的记录在 UserPreference 表中不存在则不回答问题
    • 因此,您似乎正在寻找具有单个属性的自动魔术解决方案,或者在检查 null 时基于另一个表设置数据库值的东西,包括让新对象甚至不存在,直到节省时间才真正从数据库中获取默认值?您将不得不编写一些代码来在类外实现这一点。没有自动化的 EF 解决方案可以实现这一目标。您是否有其他一些可以参考的框架或语言来满足您的要求,并且您正在寻找与之等效的东西?
    【解决方案2】:

    只要属性是公共的,实体默认从另一个表中提取数据就不会出现问题。如果您使用 setter,则需要创建一个私有字段来保存数据:

    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; }
    }
    

    这只是构造函数的替代方案,如果您需要更多地控制设置器逻辑,否则奥斯汀的答案会更容易实现

    【讨论】:

      猜你喜欢
      • 2015-01-22
      • 1970-01-01
      • 2014-08-21
      • 2016-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-08
      相关资源
      最近更新 更多