Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F#SQL表的递归类型_F#_Data Modeling_Modeling_Recursive Query_Recursive Type - Fatal编程技术网

F#SQL表的递归类型

F#SQL表的递归类型,f#,data-modeling,modeling,recursive-query,recursive-type,F#,Data Modeling,Modeling,Recursive Query,Recursive Type,我正在F#中为一个应用程序建模,在尝试为以下递归类型构造数据库表时遇到了困难: type Base = | Concrete1 of Concrete1 | Concrete2 of Concrete2 and Concrete1 = { Id : string Name : string } and Concrete2 = { Id : string Name : string BaseReference : Base } 目前我得到的解决方案(我在这里找到了灵

我正在F#中为一个应用程序建模,在尝试为以下递归类型构造数据库表时遇到了困难:

type Base = 
  | Concrete1 of Concrete1
  | Concrete2 of Concrete2
and Concrete1 = {
  Id : string
  Name : string }
and Concrete2 = {
  Id : string
  Name : string
  BaseReference : Base }
目前我得到的解决方案(我在这里找到了灵感)是:

我对这个解决方案有两个顾虑:

  • 即使在我的模型中没有意义,基表上也会有行。但我可以接受

  • 似乎查找有关Concrete2的BaseReference的所有信息的查询将非常复杂,因为我必须考虑类型的递归性和不同的具体表。此外,向模型添加新的具体类型必须修改这些查询。当然,除非SQL中有一个与
    match
    F#关键字等价的关键字


  • 我是不是太担心这些问题了?或者,有没有更好的方法在SQL表中对这种递归F#类型进行建模?

    第1部分:在关系表中对数据库数据类型进行编码

    这件事我已经挣扎过很多次了。我最终发现了在关系表中建模代数数据类型的关键:

    通过检查约束,您可以为多态类型的所有成员使用公共表,但仍然强制每个成员的不变量

    考虑以下SQL模式:

    CREATE TABLE ConcreteType (
        Id TINYINT NOT NULL PRIMARY KEY,
        Type VARCHAR(10) NOT NULL
    )
    INSERT ConcreteType
    VALUES 
    (1,'Concrete1'),
    (2,'Concrete2')
    
    CREATE TABLE Base (
        Id INT NOT NULL PRIMARY KEY,
        Name VARCHAR(100) NOT NULL,
        ConcreteTypeId TINYINT NOT NULL,
        BaseReferenceId INT NULL)
    
    GO
    
    ALTER TABLE Base
    ADD CONSTRAINT FK_Base_ConcreteType
    FOREIGN KEY(ConcreteTypeId)
    REFERENCES ConcreteType(Id)
    
    ALTER TABLE Base
    ADD CONSTRAINT FK_Base_BaseReference
    FOREIGN KEY(BaseReferenceId)
    REFERENCES Base(Id)
    
    很简单,对吧

    我们已经解决了一个问题,即通过删除抽象基类表,表中有无意义的数据。我们还组合了用于独立建模每个具体类型的表,选择将所有
    Base
    实例(不管它们的具体类型)存储在同一个表中

    照原样,此模式不限制
    Base
    类型的多态性。按原样,可以插入带有非空
    BaseReferenceId的
    ConcreteType1
    行或带有空
    BaseReferenceId的
    ConceretyPE2
    行。 没有什么能阻止您插入无效数据,因此您需要非常认真地进行插入和编辑

    这就是检查约束真正发挥作用的地方

    ALTER TABLE Base
    ADD CONSTRAINT Base_Enforce_SumType_Properties
    CHECK
    (
        (ConcreteTypeId = 1 AND BaseReferenceId IS NULL)
        OR
        (ConcreteTypeId = 2 AND BaseReferenceId IS NOT NULL)
    )
    
    检查约束
    Base\u exforce\u SumType\u Properties
    为每个具体类型定义不变量,从而在插入和更新时保护数据。继续运行所有DDL,在您自己的数据库中创建
    ConcreteType
    Base
    表。然后尝试在
    Base
    中插入违反检查约束中描述的规则的行。你不能!最后,您的数据模型保持一致

    为了解决问题#2:现在您的类型的所有成员都在一个表中(强制使用不变量),您的查询将更简单。您甚至不需要“相当于SQL中的
    match
    F#关键字”。添加新的具体类型非常简单,只需在
    ConcreteType
    表中插入新行,在
    Base
    表中添加任何新属性作为列,并修改约束以反映任何新的不变量

    第2部分:编码SQL Server中的分层(读:递归)关系

    部分担忧#2我想到了在
    ConcreteType2
    Base
    之间存在的“父子”关系中进行查询的复杂性。有很多方法可以处理这种查询,要选择一种,我们需要考虑一个特定的用例

    示例用例:我们希望查询每个
    Base
    实例,并组装一个包含每一行的对象图。这很容易;我们甚至不需要加入。我们只需要一个可变的
    字典
    ,其中
    Id
    用作键

    这里要讨论的内容很多,但需要考虑的是:有一个名为
    HierarchyID
    ()的MSSQL数据类型,它实现了“物化路径”模式,允许像您这样的层次结构更容易建模。您可以尝试在
    Base.ID
    /
    Base.BaseReferenceID
    列上使用
    HierarchyID
    而不是
    INT


    我希望这能有所帮助。

    在我看来,您的类型库大致相当于(Id,Name)元组的非空列表?是这样的,还是你为了提问而删减了这个例子?@RobertNielsen:起初我为了提问而删减了这个例子,但现在我想我会这样离开(一个(Id,Type)列表),然后我会创建另一个表来包含具体类型的公共信息,每个具体表都将使用外键引用的基本信息表。我这样做是因为否则基表将在行之间包含相同的信息。