我不确定接近我的实体设计的方式是否有缺陷,或者我是否基本上存在,但需要额外的知识。
我正在设计树状结构(递归),由节点描述,可以是树中的新级别,文件或帮助文章。文件和文章可以放在树中的多个点,因此文件和文章节点基本上是指向内容的指针。
节点描述为:
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;}
}
从这里,你有一个节点表,表明它们的父节点(在树中的位置),以及它们是什么类型。如果它们是File
或Article
,则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;}
但是,现在你实际上无法访问内容,除非你做了一个演员表(你必须从类型中找出你自己)。
我走错了路,或者几乎在那里?
答案 0 :(得分:0)
第一种方式需要您支持逻辑指针。这意味着您不能简单地删除File
对象,您必须找到并删除相应的Node
个对象。大多数时候,这是一个坏主意。但是如果你有一个这种“逻辑”关系的框架,或者你想创建一个框架,它就会非常方便。
根据我的经验,第二种方式是正确的。您需要检查Base
对象的类型,如果它是File
或Article
,但这是快速合法的操作。
您还可以考虑使用FileNode : NodeBase
和ArticleNode : NodeBase
的类型引用来制作File
和Article
类,但在许多情况下仍然需要进行类型检查。
需要了解的是,对象模型中的关系模型不支持多态性。因此,每次调用非具体类型的导航属性都会花费许多顺序请求到所有可以保存派生类型数据的表。通常,这是瓶颈。