【问题标题】:Entity Framework (code first) design thinking with multiple types具有多种类型的实体框架(代码优先)设计思维
【发布时间】:2015-04-24 10:36:30
【问题描述】:

我不确定我处理实体设计的方式是否存在缺陷,或者我是否基本上在那里,但需要额外的知识。

我正在设计一个树状结构(递归),由节点描述,这些节点可以是树中的新级别、文件或帮助文章。文件和文章可以放置在树中的多个点,因此文件和文章节点本质上是指向内容的指针。

节点描述为:

public class Node
{
    public Enum NodeType
    {
        Node,
        File,
        Article
    };

    public int Id {get;set;}
    public string Description {get;set;}
    public int ParentId {get;set;}

    public NodeType Type {get;set;}
    public int TypeId {get;set;}

    public virtual Node Parent {get;set;}
    public virtual ICollection<Node> Children {get;set;}
}

由此,您有一个节点表,指示它们的父节点(在树中的位置)以及它们的类型。如果它们是FileArticle,那么TypeId 是指向两个内容表的指针:

public class File
{
    public int Id {get;set;}
    public byte[] Content {get;set;}
}

public class Article
{
    public int Id {get;set;}
    public string Content {get;set;}
}

这样做没有问题,你会得到你所期望的。让我烦恼的是,在Node 类中,我有virtual 参数来访问父节点和子节点,它们又使用外键来完成工作,因此很容易(即不需要代码)从任何Node 向上或向下移动。

看来我的设计应该允许我添加类似于Node 类的内容,以便轻松访问内容对象,例如:

public virtual Article Article {get;set;}

public virtual File File {get;set;}

但这似乎是错误的,因为您必须为每种可能的类型添加一个新的虚拟。

另一种方法是让两种内容表类型都继承自某个允许您仅添加一个虚拟的基本类型:

public class Base
{
    public int Id {get;set}
}

public class File : Base
{
    public byte[] Content {get;set;}
}

public class Article : Base
{        
    public string Content {get;set;}
}

// Node class then gets
public virtual Base Base {get;set;}

但是,现在您实际上无法访问内容,除非您进行强制转换(您必须自己从类型中弄清楚)。

我是走错了路,还是快到了?

【问题讨论】:

    标签: c# entity-framework ef-code-first


    【解决方案1】:

    第一种方式需要您支持逻辑指针。这意味着您不能简单地删除您的File 对象,您必须找到并删除相应的Node 对象。大多数时候,这是个坏主意。但是如果你有这样一个“逻辑”关系的框架,或者你想创建一个,它会非常方便。

    根据我的经验,第二种方法是正确的。您需要检查 Base 对象的类型,如果它是 FileArticle,但这是快速且合法的操作。

    您还可以考虑使用对 FileArticle 的类型引用创建 FileNode : NodeBaseArticleNode : NodeBase 类,但在许多情况下仍然需要类型检查。

    需要理解的是,关系模型不像对象模型那样支持多态性。因此,每次调用非具体类型的导航属性都会花费您对所有可以保存派生类型数据的表的顺序请求。通常,它是瓶颈。

    【讨论】:

    • 当我创建结构时,通过使 Node 类抽象然后定义 3 个单独的子类,Node 表最终有两个额外的列 Article_IdFile_Id,它们是在FK中使用到相关内容表的Id(还有一个Discriminator列用于决定使用哪个子类)。问题是当我添加内容节点时,Article_IdFile_Id 列总是nullTypeId 列(来自我的原始帖子)与内容之间没有明显的联系。代码:pastie.org/10112152,节点 SQL:pastie.org/10112158
    猜你喜欢
    • 1970-01-01
    • 2013-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-18
    • 2013-09-22
    • 1970-01-01
    相关资源
    最近更新 更多