0

我有以下类,我真的很想在 EF 中正确映射:

internal class Wallet : EntityFrameworkEntity
{
    public Wallet()
    {
        this.Requests = new List<FinancialRequest>();
    }

    public string Name { get; set; }
    public string Description { get; set; }
    public decimal CurrentBalance { get; set; }
    public decimal BlockedBalance { get; set; }

    public virtual ICollection<Paper> Papers { get; set; }

    public virtual ICollection<FinancialRequest> Requests { get; set; }

    public virtual User Manager { get; set; }

}

internal class Request : EntityFrameworkEntity
{
    public Int64 UserId { get; set; }
    public DateTime CreatedAt { get; set; }
    public DateTime UpdatedAt { get; set; }
    public RequestStatus Status { get; set; }

    public virtual User User { get; set; }
}

internal class FinancialRequest : Request
{
    public DateTime ValidUntil { get; set; }
    public FinancialRequestType RequestType { get; set; }
    public int Quantity { get; set; }
    public bool UseMarketValue { get; set; }
    public decimal? Value { get; set; }

    public virtual Wallet Source { get; set; }
    public virtual Wallet Destination { get; set; }
    public virtual Team Team { get; set; }
}

我使用的是 Code First,所以这是我映射这些类的方法:

        modelBuilder.Entity<Wallet>()
                    .HasMany(x => x.Requests)
                    .WithOptional();

        modelBuilder.Entity<Wallet>()
                    .HasMany(x => x.Papers)
                    .WithOptional(x => x.Owner)
                    .Map(configuration => configuration.MapKey("OwnerId"));

        modelBuilder.Entity<Wallet>()
                    .HasMany(x => x.Requests)
                    .WithOptional();

        modelBuilder.Entity<Request>().ToTable("Requests");
        modelBuilder.Entity<FinancialRequest>().ToTable("FinancialRequests");

        modelBuilder.Entity<FinancialRequest>()
                    .HasRequired(x => x.Team)
                    .WithOptional()
                    .Map(configuration => configuration.MapKey("TeamId"));

        modelBuilder.Entity<FinancialRequest>()
                    .HasOptional(x => x.Destination)
                    .WithOptionalDependent()
                    .Map(configuration => configuration.MapKey("DestinationWalletId"));

        modelBuilder.Entity<FinancialRequest>()
                    .HasRequired(x => x.Source)
                    .WithRequiredDependent()
                    .Map(configuration => configuration.MapKey("SourceWalletId"));

如果我按照现在的方式保留此映射,我的数据库架构将如下所示:

错误的数据库架构

如果你仔细看,你会发现有一个名为“Wallet_Id”的列,它不应该存在。此列仅存在,因为 Wallet 类具有“Requests”集合。如果我从列中删除集合就会消失,但我需要这个集合!它代表了类之间的重要关系。我不需要的是错误生成的数据库中的第三列。

有谁知道我该如何避免这种情况?我在这里做错了什么?

4

1 回答 1

1

导致冗余外键列的问题Wallet_Id是 EF 不知道Wallet.Requests集合是否是FinancialRequest.Sourceor的反向导航属性FinancialRequest.Destination。因为它无法在两个 EF 假定Wallet.Requests根本没有反向导航属性之间做出决定。结果是与第三个 FK 的第三个冗余一对多关系。

基本上你有三个选择:

  • 删除Wallet.Requests集合,第三个关系将消失(正如您已经注意到的)。但你不希望那样。

  • 明确告诉 EF 是否Wallet.Requests具有Source Destination作为反向导航属性:

    // Remove the modelBuilder.Entity<Wallet>().HasMany(x => x.Requests) mapping
    
    modelBuilder.Entity<FinancialRequest>()
                .HasOptional(x => x.Destination)
                .WithMany(x => x.Requests)
                .Map(config => config.MapKey("DestinationWalletId"));
    
    modelBuilder.Entity<FinancialRequest>()
                .HasRequired(x => x.Source)
                .WithMany()
                .Map(config => config.MapKey("SourceWalletId"));
    

    在两者之一中使用WithMany(x => x.Requests)Destination在示例中,它也可以是Source),但不能在两者中使用

  • 引入第二个集合Wallet并将这两个集合分别映射到SourceDestination

    internal class Wallet : EntityFrameworkEntity
    {
        public Wallet()
        {
            this.SourceRequests = new List<FinancialRequest>();
            this.DestinationRequests = new List<FinancialRequest>();
        }
    
        // ...
    
        public virtual ICollection<FinancialRequest> SourceRequests { get; set; }
        public virtual ICollection<FinancialRequest> DestinationRequests { get; set; }
    }
    

    映射:

    // Remove the modelBuilder.Entity<Wallet>().HasMany(x => x.Requests) mapping
    
    modelBuilder.Entity<FinancialRequest>()
                .HasOptional(x => x.Destination)
                .WithMany(x => x.DestinationRequests)
                .Map(config => config.MapKey("DestinationWalletId"));
    
    modelBuilder.Entity<FinancialRequest>()
                .HasRequired(x => x.Source)
                .WithMany(x => x.SourceRequests)
                .Map(config => config.MapKey("SourceWalletId"));
    

顺便说一句:不应该两者都 Source需要Destination吗?如果是,您可以替换HasOptionalby,HasRequired但您必须附加WillCascadeOnDelete(false)到两个映射中的至少一个,以避免多个级联删除路径异常。

于 2013-04-01T16:00:06.873 回答