实体框架映射多级属性

Posted

技术标签:

【中文标题】实体框架映射多级属性【英文标题】: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 中加载它?

【问题讨论】:

【参考方案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; 

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

【讨论】:

以上是关于实体框架映射多级属性的主要内容,如果未能解决你的问题,请参考以下文章

实体框架将集合属性映射到一列

如何查询实体框架中的非映射属性?

在实体框架中将对象类型属性映射到 varbinary(MAX)

实体框架 - 代码优先:使用相同类型的多个子/可选属性进行映射

在实体框架中获取属性的映射列名称

实体框架 CTP4 代码优先:映射受保护的属性