我不确定我处理实体设计的方法是否存在缺陷,或者我是否基本上做到了,但需要额外的知识。
我正在设计一个树状结构(递归),由节点描述,节点可以是树中的新级别、文件或帮助文章。文件和文章可以放置在树中的多个点,因此文件和文章节点本质上是指向内容的指针。
节点描述为:
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;}
但是,现在您实际上无法访问内容,除非您进行强制转换(您必须自己从类型中弄清楚)。
我是走错了路还是快走错了?
最佳答案
第一种方式要求您支持逻辑指针。这意味着您不能简单地删除 File
对象,您必须找到并删除相应的 Node
对象。大多数时候,这是个坏主意。但是,如果您有这种“逻辑”关系的框架,或者您想要创建一个,它会非常方便。
根据我的经验,第二种方法是正确的。您需要检查 Base
对象的类型,如果它是 File
或 Article
但这是快速且合法的操作。
您还可以考虑制作 FileNode : NodeBase
和 ArticleNode : NodeBase
类,其中包含对 File
和 Article
的类型化引用>,但在许多情况下仍然需要类型检查。
需要了解的是,关系模型不像对象模型那样支持多态性。因此,每次调用非具体类型的导航属性都会花费您对所有可以保存派生类型数据的表的许多顺序请求。通常,这是瓶颈。
关于c# - 具有多种类型的 Entity Framework (代码优先)设计思维,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29845258/