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

时间:2013-08-06 12:56:11

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

假设我有一个简单的数据库示例,例如

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对象列表作为属性?或者更一般地说,我认为,当联结表不仅仅包含两个表的主键副本时,这是建模多对多关系的正确方法吗?我最终将学习实体框架,但我想在学习的同时更接近金属。

3 个答案:

答案 0 :(得分:1)

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

一种方法可能是延迟加载。因此,请考虑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

另一种更老套的方法是在构建Item列表时传入VisitItemVisit个对象。

最后,另一种更具可扩展性的方法是利用缓存和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
}

这真的没什么不同。

答案 1 :(得分:0)

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

  • 如果您必须更新项目的ExpirationDate,会发生什么?

  • 如果您要修改访问(添加其他项目)会发生什么?

此类主题的起点可能是:http://en.wikipedia.org/wiki/Database_normalization#Normal_forms

编辑:我并不是说这是一个糟糕的解决方案,只是指出了额外的负担,特别是在没有使用ORM的情况下。欢迎来自downvoters的评论。

答案 2 :(得分:-1)

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

访问具有属性项目访问权限 项目还具有属性项目访问