【问题标题】:Mapping Table in DB first without foreign key在没有外键的情况下首先在数据库中映射表
【发布时间】:2023-01-11 05:14:15
【问题描述】:

我有一个用数据库优先方法编写的程序;我有一个表 ServicePlan 和另一个 ServicePlanDetails。它们没有相互映射,但是它们有一个共同的列PlanId;一个servicePlan可以包含多个ServicePlanDetails,就像它的列表一样。

我不想对数据库进行任何更改,但我也想映射它们。我怎样才能做到这一点?在创建模型的方法中执行此操作是否会为我完成工作并且不会更改数据库中的任何内容?我试过这个但可以得到结果。

为简单起见,我只添加了几列及其映射,而不是全部:

public partial class ServicePlan
{
    public ServicePlan()
    {
        ServicePlanDetails = new HashSet<ServicePlanDetail>();
    }

    public long PlanId { get; set; }
    public decimal PhoneId { get; set; }
    public byte? NLines { get; set; }
    public DateTime? DateStart { get; set; }
    public DateTime? DateEnd { get; set; }
    public virtual ICollection<ServicePlanDetail> ServicePlanDetails { get; set; }
}

public partial class ServicePlanDetail
{
    public long PlanId { get; set; }
    public string? ServCode { get; set; }
    public string? CountryCode { get; set; }
    public bool? IsPlan { get; set; }
    public decimal? Cost { get; set; }
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<ServicePlan>(entity =>
    {
        entity.HasKey(e => e.PlanId).HasName("PK_UsersPlan");

        entity.ToTable("ServicePlan");

        entity.HasIndex(e => e.VideoTronId, "IDX_VTID").HasFillFactor(80);

        entity.HasIndex(e => new { e.PhoneId, e.IsApproved }, "Ix_SrvcPlan").HasFillFactor(80);

        entity.Property(e => e.Zone).HasMaxLength(50);
        entity.HasMany(p => p.ServicePlanDetails)
            .WithOne()
            .HasPrincipalKey(p => p.PlanId)
            .HasForeignKey(p => p.PlanId);
    });
}

我得到的错误是:

无法确定类型为“ICollection”的导航“ServicePlan.ServicePlanDetails”表示的关系。手动配置关系,或使用“[NotMapped]”属性或使用“OnModelCreating”中的“EntityTypeBuilder.Ignore”忽略此属性。

我想将与serviceplan 具有相同planidserviceplandetails 放入serviceplan 的列表中。

【问题讨论】:

  • 试用 EF Core 电动工具

标签: c# entity-framework-core


【解决方案1】:

PlanId 不能同时是一对多的外键和主键。

public partial class ServicePlanDetail
{
    public long Id { get; set; }
    public long PlanId { get; set; }
    public string? ServCode { get; set; }
    public string? CountryCode { get; set; }
    public bool? IsPlan { get; set; }
    public decimal? Cost { get; set; }
}

配置

 entity.HasMany(p => p.ServicePlanDetails)
            .WithOne()
            .HasPrincipalKey(p => p.PlanId)
            .HasForeignKey(p => p.PlanId);

【讨论】:

  • 那么我不明白你的回答怎么办?
  • 您应该将 Id 列添加到 ServicePlanDetail
  • 但是如果我不能对数据库进行任何更改怎么办,因为这样我必须向表中添加一个主键列 ID,如果我添加它,我必须在映射时在函数中提及它
【解决方案2】:

如果在数据库中,一个计划可以有多个 ServicePlanDetails,并且您通过计划 ID 链接它们,您如何区分一个 ServicePlanDetail 与该计划的另一个?是什么让两个 ServicePlanDetail 记录独一无二?这就是你问题的症结所在。您的 FK 映射是正确的,但如果 PlanId 是 ServicePlanDetail 上的 PK,它将不起作用。 PK 必须唯一标识单个记录。例如,如果您的计划与应用于不同用户的服务计划详细信息相关联,其中多个用户引用同一计划并且 ServicePlanId 上有一个 UserID,则 PK 应该是 PlanId + UserId 的组合。

作为 DB-First 方法,数据库应该已经设置了 PK 和约束。您只需设置 EF 键和关系类型来匹配它。

现在,如果 ServicePlanDetail 的 PK 仅声明为 PlanId,那么答案就是 Plan 和 ServicePlanDetail 之间的关系是一对一,而不是一对多。这变成了.HasOne(p =&gt; p.ServicePlanDetail).WithOne(sp =&gt; sp.Plan),如果不改变数据关系,您真的无能为力。如果基础数据库架构不支持该关系,则您无法神奇地更改 EF 将使用的关系。

【讨论】:

    猜你喜欢
    • 2023-03-08
    • 2014-04-09
    • 2016-05-23
    • 2014-06-06
    • 2016-05-10
    • 2018-09-22
    • 2022-09-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多