使用连接表与单向查找

时间:2018-03-06 20:01:49

标签: .net sql-server entity-framework

我们将在数据库中存储多个对象的注释,例如Customer,Product,Order等。每个条目都可以有多个注释。对于主键,我们将使用GUID。传统上,我们会为上面做一个连接表,例如Customer_Comment,Order_comment,Product_Comment等。

由于我们将始终从订单或客户或产品中查找评论,因此我们只需要单向查找。我们永远不需要查找注释所属的实体,我们只需要为特定实体加载注释。有人建议不要使用Join表,而是在Comment表上有一个LinkId字段,它记录所有实体的Guid,例如Customer Id或Product Id。然后,我们可以查找属于特定实体的所有注释,因为Guids是唯一的,所以不会有任何冲突。

我想知道在数据库存储和查找效率方面是否存在使用此类架构的任何缺点。此外,我们将只使用实体框架,可能不直接查询Db。在这方面我们将采用这种方法遇到什么问题?

编辑:评论表:ID(guid),Text,LinkId(Guid)。 LinkId将链接到客户,产品等实体

2 个答案:

答案 0 :(得分:0)

使用单个表进行注释会给配置EF关系带来困难。所以你最好坚持每个实体使用单独的评论表。

答案 1 :(得分:0)

在我看来,你有像客户,产品,订单等类。并且你在这些和评论之间有一对多的关系:每个客户都有零个或多个评论,每个评论都属于一个客户。

其中一个问题是您计划使用的表将丢失数据库规范化。您不打算使用CustomerComments,ProductComments和OrderComments,而是使用带有一个外键的注释,有时使用Customer表,有时使用Product表等。

我认为重新考虑这是否是你真正想要的是明智之举。在您当前的版本中,所有注释都具有相同的布局,但是如果在将来的版本中您希望CustomerComment与ProductComment不同,那该怎么办?

此外,因为您将所有注释放在一个表中,所以所有查询都会变慢。可以删除客户而不删除他的评论,留下不属于任何内容的评论。在正确规范化的数据库中,这是不可能的,您的数据库管理系统会注意每个外键都指向某个东西。

所以我的建议是创建一个包含CustomerComments的表,一个包含ProductComments的表。所有这些表聚合了Comments类,并拥有正确的Customer / Product等的外键。如果你真的想要,你可以继承类来自评论,但我很少看到任何好处。

所以我的建议是:

class Comment
{
    public string Name {get; set;}
    public string Text {get; set;}
    ...
}

class Customer
{
    public Guid Id {get; set;}

    // every Customer has zero or more Comments (one-to-many)
    public virtual ICollection<CustomerComment> Comments {get; set;}

    ... // other Customer properties
}

class CustomerComment
{
    public Guid Id {get; set;}

    // every CustomerComment belongs to exactly one Customer using foreign key
    public Guid CustomerId {get; set;}
    public virtual Customer Customer {get; set;}

    public Comment Comment {get; set;}
    ... // free to add other properties in future versioins,
        // without disturbing ProductComments
}

Product and ProductComment的类似课程。

class MyDbContext : DbContext
{
    public DbSet<Customer> Customers {get; set;}
    public DbSet<Product> Products {get; set;}

    public DbSet<CustomerComment> CustomerComments {get; set;}
    public DbSet<ProductComment> ProductComments {get; set;}
}

好消息是,如果你有一个CustomerId,用这个Id得到客户的评论会更快:

var commentsOfCustomerWithId = myDbContext.CustomerComments
    .Where(customerComment => customerComment.CustomerId == CustomerId)
    .Select(customerComment => Comment);

以下是实体框架的更好的功能。如果您有CustomerId,并且您希望“客户带有他的评论”,则无需进行加入:

var customerWithHisComments = myDbContext.Customers
   .Where(customer => customer.Id == customerId)
   .Select(customer => new
   {
       // select only the properties you plan to use:
       Name = customer.Name,
       Address = customer.Address,
       ...

       Comments = customer.Comments.Select(comment => new
       {
           // again select only the comment properties you plan to use:
           Text = comment.Text,
           Category = comment.Category,
           ...
       })
       .ToList(),
   })
   .SingleOrDefault();

好消息是,即使此客户没有评论,您也可以获得带有评论的正确填充(空)列表。

将数据从数据库传输到本地计算机是较慢的部分之一。因此,仅选择您计划使用的属性始终是明智的,而不是选择完整的项目。例如,如果拥有Id 100的客户有400条评论,那么所有这400条评论的CustomerId都为100.如果您将所有房产的所有房产转移到他的所有评论,您将转移数字100超过400次,而你甚至可能不会使用它,或者可能只使用一次(因为你知道它们都具有相同的值)