在没有 ORM 的情况下对多对多关系进行建模

本文关键字:关系 建模 情况下 ORM | 更新日期: 2023-09-27 18:26:33

假设我有一个简单的数据库示例,类似于

create table Items
(ItemId int
,ItemName varchar(50)
,ItemCost decimal
,ItemOrigin varchar(50) --maps to reference of country codes
,primary key (ItemId)
)
go
create table Visits
(VisitId int
,VisitDate datetime
,VisitLocation varchar(50) --maps to references of country codes
,primary key (VisitId)
)
go
create table ItemsVisits
(ItemId int
,VisitId int
,ItemsPurchased int
,ItemExpirationDate datetime
,TotalCost decimal --equals price * items purchased
,primary key(ItemId,VisitId)
)

public class Items
    {
        public int ItemId { get; set; }
        public string ItemName { get; set; }
        public decimal ItemCost { get; set; }
        public string ItemOrigin { get; set; }
    }
    public class Visits
    {
        public int VisitId { get; set; }
        public DateTime VisitDate { get; set; }
        public string VisitLocation { get; set; }
        public List<Items> ItemsPurchased { get; set; }
    }

上面的两个简单课程是我的第一个倾向。 在此示例中,Items表是可以购买的内容的参考表,应用程序的"肉"位于Visits表中。 使用上面的当前设置,我无法知道所购买物品的到期日期。(在这种情况下,假设某个 ItemId 随其到期日期而变化,具体取决于购买日期(。 我应该添加一个类似的类

 public class ItemsVisits
    {
        public int ItemId { get; set; }
        public int VisitId { get; set; }
        public int ItemsPurchased { get; set; }
        public DateTime ItemExpirationDate { get; set; }
        public decimal TotalCost { get; set; }
    }

然后使Visits表具有ItemsVisits对象列表作为属性? 或者更一般地说,我想,当连接表不仅仅包含两个表的主键副本时,这是对多对多关系进行建模的正确方法吗?我最终会学习实体框架,但我想在学习时更接近金属。

在没有 ORM 的情况下对多对多关系进行建模

是的,构建ItemVisits类,然后通过集合提供一对多关系是正确的方法。另一个感兴趣的项是,当您查询它时,您需要一种方法来返回Visits并从ItemVisits Items。当然,这是一种更具体的方式,说你需要一种从实体到实体的抽象方式。

一种方法可能是延迟加载。因此,请考虑 ItemVisits 类上的几个新属性:

private Item _baseItem;
public Item BaseItem
{
    get
    {
        if (_baseItem != null) { return _baseItem; }
        // go get the item here and set the internal property
    }
}

您需要这样做的原因很清楚。假设您正在查询ItemVisits并且想要包含Item.ItemName,那么您实际上无法这样做,因为您没有Item

另一种更老式的方法是在构造ItemVisit列表时传入ItemVisit对象。

最后,另一种更具可扩展性的方法是利用缓存和 IoC。通过这种方式,您可以利用 ItemVisit 类的构造函数并通过 IoC 注入这些值。我不建议这样做除非您有大量的事务负载并且有理由相信您将以荒谬的速度构建这些对象。当我说重要时,我说的是数百万笔交易。

编辑:对于多个主键:

如果我有一个只有两个主键的表:

public class LinkTable
{
    // exists in the table
    public int ItemId { get; set; }
    private Item _refItem;
    public Item RefItem
    {
        get
        {
            if (_refItem != null) { return _refItem; }
            // go get the item
        }
    }
    // exists in the table
    public int VisitId { get; set; }
    private Visit _refVisit;
    public Visit RefVisit // sample impl as above
}

真的没有什么不同。

在此类表中添加多个主键会导致数据重复,这可能会导致问题:

  • 如果您必须更新项目的到期日期,会发生什么情况?

  • 如果您要修改访问(添加其他项目(会怎样?

该主题的起点可以是:http://en.wikipedia.org/wiki/Database_normalization#Normal_forms

编辑:我并不是说这是一个糟糕的解决方案,只是指出了额外的可能负担,尤其是在不使用ORM的情况下。欢迎反对者发表评论。

oo中的多对多关系是不同的。

访问

有适当的项目访问项目也有适当的项目访问