【问题标题】:Entity Framework "source" table approach实体框架“源”表方法
【发布时间】:2020-04-10 04:00:34
【问题描述】:

我认为这是一个微不足道的问题,但想问你有关它的干净解决方案。

这一次,我的数据库中有一个表Cards,已经填满了几千行。我想将此表视为只读数据源,其中包含用户可以存储在其集合中的所有可能项目。

当我为此模型创建迁移时,它会不断向Cards 表添加一个CollectionsId 列,我完全理解,但这是我想避免的。

我的问题是:我应该为UserCard 之类的卡片创建额外的类并将其用于收藏吗?如果是这样,那么它会产生一个问题,因为它迫使我用Card 验证UserCard 是否有效。它应该存储在单独的上下文中吗?解决此类问题的最佳方法是什么?

abstract class Entity
{
    public int Id { get; set; }
}

class Card : Entity
{
    public string Name { get; set; }
    public string Set { get; set; }
}

class User : Entity
{
    public string Name { get; set; }
    public List<Collection> Collections { get; set; }
}

class Collection : Entity
{
    public User User { get; set; }
    public string Name { get; set; }
    public List<Card> Cards { get; set ;}
}

【问题讨论】:

  • 它没有回答你的问题,但你真的不应该使用基础实体类。它不会为您带来任何好处,并且会不必要地使模型复杂化。
  • 这是为什么呢?我在很多解决方案中都见过它,它似乎对泛型类或接口很方便。
  • Base Entity 与此问题无关,并且是一个非常好的 OO 实践,尤其是在这里,您声明所有实体都将具有一个整数 Id 字段。快乐的编码,这种设计选择将简化您的旅程。
  • class Collection 让我很困惑。是bridge-tableUserCard 之间建立many-to-many 关系吗?您的数据库中有多少张表?你能列出你的桌子吗?

标签: c# asp.net-mvc entity-framework-core


【解决方案1】:

因为您已定义 Collection 包含许多卡片,所以 EF 代表您注入的默认实现是在 Collection 表中包含一个 外键 列,以跟踪哪个 Collection 和 @ 987654325@所属。

作为 EF 迁移的一部分注入的附加字段称为 Shadow Properties 这些属性是模型的一部分,也是确保模型功能的必要组件您声明它的方式,但这些属性未在您的类结构中定义(这意味着您不能在查询或代码中使用它们)

Shadow Foreign Key Properties 是在 OPs 模型中注入的特定字段类型。

解决此问题的一种方法是将Collection 的定义更改为拥有单个卡片引用,而不是拥有一组卡片,这种设计选择将要求您有一个额外的列,以便您跟踪集合的“名称”(或您将在应用中管理的另一个 ID)

  • 这将在数据模式方面起作用,但查询和使用时会不太直观,因为现在 Collection概念 变得更加抽象。对于像这样的小型项目,让数据库表和概念与您的业务领域保持一致确实很有帮助。

解决这个问题的另一种方法是在 Collection 和 Card 之间创建一个链接表,这本身并不是一个糟糕的设计,Card 真的变成了一个 Card Definition(通常称为 Card Type),您可以创建一个名为CollectionCard 的新表,用于指定已添加到集合中的卡片。

您可以进行的下一个实现更改是删除 EF 在引入 Shadow Properties 以支持您在数据库中的类结构并完全定义所需的指向字段,然后您可以轻松地使用属性表示法来声明用于记录外键链接的特定字段。

abstract class Entity
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
}

/// <summary>Definition of all 'available' types of card</summary>
/// <remarks>It might make sense to refer or rename this table to CardType</remarks>
class Card : Entity
{
    public string Name { get; set; }
    public string Set { get; set; }
}

class User : Entity
{
    public string Name { get; set; }
    public virtual List<Collection> Collections { get; set; } = new HashSet<Collection>();
}

class Collection : Entity
{
    public int UserId { get;set; }
    [ForeignKey(nameof(UserId))]
    public User User { get; set; }

    public string Name { get; set; }
    public virtual List<CollectionCard> Cards { get; set; } = new HashSet<CollectionCard>();
}

class CollectionCard : Entity
{
    public int CollectionId { get;set; }
    [ForeignKey(nameof(CollectionId))]
    public virtual Collection Collection { get; set; }

    public int CardId { get; set; }
    [ForeignKey(nameof(CardId))]
    public virtual Card Card { get; set; }
}

这种结构在纸牌游戏类型的场景中很有用,因为您可以轻松导入/导出卡牌定义列表,而不会对数据集的其余部分造成太多不利的问题。

请注意,我通过使用KeyAttribute 装饰Id 字段为您的Entity 基类增加了价值。虽然 EF 在 Convention-Only 方法中运行良好,但我建议在使用属性表示法之间混合使用,尤其是对于所有 ForeignPrimary 键配置,并允许模型约定管理不太重要的结构定义。

为属性表示法不可行或约定不适合您的情况保留流畅的模型表示法。 - 这个建议是基于这样一个现实,即随着模型的增长,很难找到/保持流畅的符号,每个字段都包含属性符号,这是当你不知道字段做什么时的主要参考点在你的模型中。

【讨论】:

    猜你喜欢
    • 2013-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多