项目返工:我应该使用主复合键和 json 来翻译 Laravel 吗?

Project rework : Should I use primary composite keys and json for translations with Laravel?

上下文

我正在使用 Laravel 7 和 Mysql 完全改造网站(代码和数据库)。
目标是通过充分利用最佳实践来重建整个项目。
在这个项目中,我有很多数据库表和它们之间的关系,我也在处理很多用户定义的内容。

问题 1

在关系数据库设计中,当您知道 id 无用(例如数据透视表)时,使用 composite primary keys 是一个很好的做法。
但我知道 Laravel 不处理 composite primary keys 模型和关系,你必须安装一些外部包或自己做 Trait/Class 继承。

所以,我想知道我是否应该使用 composite primary keys,或者我是否应该坚持使用默认的自动递增 id 以及 composite unique key?

为了举例说明我的意思,我必须在想法 1 或想法 2 之间做出选择,或者可能是其他选择?

想法 1:使用标准主键

Schema::create('user_documents', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->constrained();
    $table->foreignId('document_id')->constrained();
    $table->string('file_name', 50);
    $table->json('comments')->nullable();
    // [...] Maybe some more columns
    $table->timestamps();

    $table->unique(['user_id', 'document_id']);
});

思路二:复合主键

Schema::create('user_documents', function (Blueprint $table) {
    $table->foreignId('user_id')->constrained();
    $table->foreignId('document_id')->constrained();
    $table->string('file_name', 50);
    $table->json('comments')->nullable();
    // [...] Maybe some more columns
    $table->timestamps();

    $table->primary(['user_id', 'document_id']);
});

问题 2

您可能已经注意到我为 comments 列使用了 json 类型。
那是因为用户在上传文件时可以用一种或多种语言写评论。

此列的值如下所示:

{
    "en": "a comment in english",
    "fr": "a comment in french",
    "*": "the comment for all other languages"
}

如果他希望无论使用哪种语言,每个人都能看到相同的文本,我们可以这样做:

{
    "*": "the comment for all languages"
}

对于用户定义的多语言内容,我有很多这样的工作,我认为这种方法比使用特定的翻译表要好。

但我不确定使用那么多 json 列是否是一个好习惯,有没有更好的翻译方法?

您提出了很多需要回答的好问题。我们没有任何关于您 "issues" 精确的上下文,但您为我们提供了相当多的信息,这些信息有助于我们理解您的要求。

这是我的两分钱:

问题 1

您指出了 composite primary keyscomposite unique keys SQL 这两个概念,这些概念非常适合处理组合键以引用与您的应用模型相关的内容。正如 4 年前(那么多!) 首次指出的那样,今天确实还没有办法让 Eloquent 本地工作。但是有一些解决方法可以使它工作得很好。

我更愿意使用 composite primary keys 来确保基础非常牢固,避免在数据库中推送行时出错。我想说的是,这取决于您对开发应用程序时可能忘记的潜在错误或差距的某种容忍度。

我不太喜欢第 1 个想法,因为在我看来,在这里使用自动递增密钥没有任何美妙和务实的理由。我始终牢记 "KISS" principle ("Keep it stupid simple")。 SQL 提供了一种本地组合键的方法(并且它在一般用途中工作得很好),"why would I go with one more key if it doesn't fit with a real useful feature of my app ?"

Laravel 已经成长了很多,但每个月都在不断更新和改进。我非常喜欢这个框架,但它总是缺少有价值的东西,这就是开源如此重要的原因。它提供了一些创建 TraitsInterfaceHelpers 的方法,可以通过几个主键检索、更新和查找行,正如您可能已经知道的那样,所以不要花太多钱很多时间 ;只要确保它符合您的需求,您就可以通过它轻松地操作您的模型。创建您自己的 HasCompositePrimaryKey 特征,您可以在其上定义新的主键 属性 :protected $primaryKey = array('key1', 'key2');(请检查 )。

问题 2

事实上,我也认为 json 是处理多语言字符串值的最佳字段类型。 MySQL (8.0) 的最新版本对 searching content in JSON objects 做了很多改进,你可能想看看。对于多种语言,我也会将所有字符串存储在同一行中,就像您为 comments table 所做的那样。这将使您能够根据您的用户或访问者的语言选择轻松地检索、显示和操作内容。您可以将 2 个字母的 iso lang 代码存储到用户会话 cookie 中,并在您的 Blade 模板中使用它,这样使用起来会简单得多:$comment[$user_lang_key] 其中 $user_lang_key 可以从一些有点像 Session::get('settings_lang_key').

我真的不知道显示与 "all other languages" 不可用的不同评论的目的是什么。我更愿意使用现有的语言作为我的应用程序的后备,比如英语语言,它被大量使用并显示了很多默认值。您必须简单地将会话语言键回退到 en 才能使其在任何地方都能正常工作。放置某种 "alias" 之类的 '*' 会使这有点混乱,并且可能需要您进行一些预验证才能正确使用它。如果你想让你的用户选择以他想要的语言显示评论,就像你在评论中所说的那样,我宁愿将这个设置值保存在你的数据库中的某个地方,并用它来指向所选的语言。

此外,如果您需要它(因为您的应用程序的用户可以设置您的应用程序的某些行为),下面是我将如何处理他可以在我的电子商务应用程序中创建的多语言设置:

{
    "fr": {
        "title": "Choix d'un T-Shirt",
        "fields": [
            {
                "label": "Taille de T-Shirt",
                "type": "single-choice",
                "choices": [
                    { "name": "S", "price": 10 },
                    { "name": "M", "price": 15 }
                ]
            },
            {
                "label": "Couleur",
                [...]
            }
        ]
    }, 
    "en": {
        "title": "T-Shirt Selection",
        "fields": [
            {
                "label": "T-Shirt Size",
                "type": "single-choice",
                "choices": [
                    { "name": "S", "price": 10 },
                    { "name": "M", "price": 15 }
                ]
            },
            {
                "label": "Color",
                [...]
            }
        ]
    }
}

最后,一切都取决于你,但我想分享我的知识以及我目前在我身边所做的事情,而不需要任何痛苦来处理多语言功能。我希望这会以您想象的最佳方式为您提供一些适合您需求的想法。