建模1:1双面可选关系

时间:2016-08-17 15:00:04

标签: sql entity-framework database-design

我有三个实体:

  • User - 可以有多个Reviews,可以有多个Transactions
  • Transaction - 必须有FromUserToUser,可以有FromUserReviewToUserReview
  • Review - 可以有Transaction,必须有FromUserToUser

这个想法是用户可以互相撰写评论,可以互相发送付款。用户只能为另一个用户写一个非交易评论 - 否则,评论必须附加到交易。

基本上,这将成为交易和评论之间的1:1双向可选关系。我正在考虑使用包含以下内容的连接表对此进行建模:

  • ReviewId
  • TransactionId

并将其称为TransactionReview。这似乎消除了模型/代码重复,但使我的业务逻辑复杂化。

我看到的另一个选择是创建两个实体:UserReviewTransactionReview - 这将简化逻辑,但会强制我进行代码重复,并且有两个表应该是单个实体。

正确的方法是什么?我正在使用实体框架代码优先,以防万一。

2 个答案:

答案 0 :(得分:1)

我可能会选择一个简单的数据模型:

  • User
  • Transaction(不存储有关评论的信息)
  • Review(评论必须针对特定用户或交易)

您可以通过它的类型(字典表)来区分评论,以了解哪个评论是独立的,哪些评论是与事务一起提供的。

你可以采取两种方式:

  • 有两列用于存储TransactionUser实体的ID,并根据类型保留空值
  • 或者有一列可以通过审核类型识别实体的ID

我认为不需要TransactionReview实体,因为一次审核只能附加到0..1交易。由于交易可以有0..2评论,这与可选的零元素成为一对多的关系。

我同意它可能会使检索的逻辑复杂化(必须记住这一点),但我发现在处理这样建模的数据时非常方便。

答案 1 :(得分:1)

我准备了一些代码,请检查并尝试。

public class User
{
    // properties
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual Address Address { get; set; }
    public virtual ICollection<UserReview> UserReviewsFromMe { get; set; }
    public virtual ICollection<UserReview> UserReviewsToUsers { get; set; }
    public virtual ICollection<TransactionReview> TransactionReviews { get; set; }
}

public class Review
{
    public int Id { get; set; }
    public string Content { get; set; }
    public string EntityName { get; set; }
    public int EntityId { get; set; }

    public virtual TransactionReview TransactionReview { get; set; }
    public virtual UserReview UserReview { get; set; }
}

public class Transaction
{
    public int Id { get; set; }
    public string Note { get; set; }
    public DateTime CreatedOnUtc { get; set; }

    public virtual ICollection<TransactionReview> TransactionReviews { get; set; }
}

public class UserConfiguration : EntityTypeConfiguration<User>
{
    public UserConfiguration()
    {
        ToTable("User");
        HasKey(p => p.Id);

    }
}

public class ReviewConfiguration : EntityTypeConfiguration<Review>
{
    public ReviewConfiguration()
    {
        ToTable("Review");
        HasKey(x => new { x.Id });
    }
}

public class TransactionConfiguration : EntityTypeConfiguration<Transaction>
{
    public TransactionConfiguration()
    {
        ToTable("Transaction");
        HasKey(x => new { x.Id });
    }
}

public class UserReview
{
    public int Id { get; set; }
    public int FromUserId { get; set; }
    public int ToUserId { get; set; }

    public virtual User FromUser { get; set; }
    public virtual Review Review { get; set; }
    public virtual User ToUser { get; set; }
}

public class TransactionReview
{
    public int Id { get; set; }
    public int TransactionId { get; set; }
    public int UserId { get; set; }

    public virtual Transaction Transaction { get; set; }
    public virtual Review Review { get; set; }
    public virtual User User { get; set; }
}

public class UserReviewConfiguration : EntityTypeConfiguration<UserReview>
{
    public UserReviewConfiguration()
    {
        ToTable("UserReview");
        HasKey(x => new { x.Id });
        Property(a => a.Id).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None);

        this.HasRequired(ur => ur.FromUser)
            .WithMany(u => u.UserReviewsFromMe)
            .HasForeignKey(ur => ur.FromUserId)
            .WillCascadeOnDelete(false);

        this.HasRequired(ur => ur.Review)
            .WithOptional(r => r.UserReview);

        this.HasRequired(ur => ur.ToUser)
            .WithMany(u => u.UserReviewsToUsers)
            .HasForeignKey(ur => ur.ToUserId)
            .WillCascadeOnDelete(false);
    }
}

在上面的UserReviewConfiguration类中,我映射如下:用户可以发布零个或多个UserReview,UserReview仅由一个用户发布,并且只能为一个用户发布,并与一个评论映射只有,如果有人需要,审查和用户实体也是独立的。

public class TransactionReviewConfiguration : EntityTypeConfiguration<TransactionReview>
{
    public TransactionReviewConfiguration()
    {
        ToTable("TransactionReview");
        HasKey(x => new { x.Id });
        Property(a => a.Id).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None);

        this.HasRequired(tr => tr.Transaction)
            .WithMany(t => t.TransactionReviews)
            .HasForeignKey(tr => tr.TransactionId);

        this.HasRequired(tr => tr.Review)
            .WithOptional(r => r.TransactionReview);

        this.HasRequired(tr => tr.User)
            .WithMany(u => u.TransactionReviews)
            .HasForeignKey(tr => tr.UserId);
    }
}

在上面的TransactionReviewConfiguration类中,我的映射如下:一个用户可以发布零个或多个TransactionReview,一个用户只发布一个TransactionReview,只能用于一个Transaction,并用一个评论映射只有,如果有人需要,也可以使用户,评论和交易实体独立。

希望这会有所帮助......