【问题标题】:Use foreign keys as primary key使用外键作为主键
【发布时间】:2013-10-08 14:05:00
【问题描述】:

我有一个包含很多关系的数据库。不幸的是,它是一个旧的维护数据库,似乎不理解关联或键的概念,有时它缺乏。它的主要用途是在另一个应用程序中,因此我最不愿意更改数据库(而是配置实体框架)

我遇到的问题是尝试将外键用作主键,因为(我猜)关联表使用它。

我的表被称为

Operation{    Criteria {    Parameter{    CriteriaSelection {
  ID            ID,           ID,           ID,
  ..            ..            ..            ..
}             }             }             }

CheckpointOperation {
  ID,
  Criteria_ID,
  ..
}

CheckpointParameter {
  // missing primary key
  CheckpointOperation_ID,  // a CheckpointOperation has many CheckpointParameters
  CriteriaSelection_ID,    // a CheckpointParameter has one CriteriaSelection
  Parameter_ID,            // .. and one Parameter
  ..
}

这里的问题是CheckpointParameter没有专门定义任何主键,而是{ CheckpointOperation_ID, CriteriaSelection_ID, Parameter_ID }的主键。现在我正在尝试使用class CheckpointParameterMap : EntityTypeConfiguration<CheckpointParameter> 将其映射到EntityFramework 中。

public class CheckpointOperation
{
    public int Id { get; set; }
    public virtual Operation Operation { get; set; }

    public virtual ICollection<CheckpointParameter> Parameters { get; set; }
}

public class CheckpointParameter
{
    public int OperationId { get; set; }

    public virtual CheckpointOperation CheckpointOperation { get; set; }
    public virtual CriteriaSelection Criteria { get; set; }
    public virtual QualityParameter Parameter { get; set; }
}

public class CheckpointParameterMap : EntityTypeConfiguration<CheckpointParameter>
{
    public CheckpointParameterMap()
    {
        HasKey(p => new { p.OperationId });

        Property(p => p.OperationId)
            .HasColumnName("CheckpointOperation_ID");

        HasRequired(p => p.CriteriaSelection)
            .WithRequiredDependent()
            .Map(map => map.MapKey("CriteriaSelection_ID"));

        HasRequired(p => p.Parameter)
            .WithRequiredDependent()
            .Map(map => map.MapKey("Parameter_ID"));

        HasRequired(p => p.CheckpointOperation)
            .WithMany(o => o.CheckpointParameters)
            .HasForeignKey(p => p.OperationId);
    }
}

但这给了我一个错误

多重性在关系“CheckpointParameter_CheckpointOperation”中的角色“CheckpointParameter_CheckpointOperation_Source”中无效。因为从属角色引用关键属性,所以从属角色的多重性的上限必须是'1'。\r\n"}

所以我试图删除HasKey,但这给了我一个错误

EntityType 'CheckpointParameter' 没有定义键。定义此 EntityType 的键。\r\n\tSystem.Data.Entity.Edm.EdmEntitySet: EntityType: EntitySet 'CheckpointParameters' 基于没有定义键的类型 'CheckpointParameter'。\r\n"}

然后我尝试在主键中使用外部 CriteriaSelectionId,因为我有列名:

public class CheckpointParameter
{
    ...
    public int CriteriaSelectionId { get; set; }
    ...
}

public CheckpointParameterMap()
{
    HasKey(p => new { p.OperationId, p.CriteriaSelectionId });
    //...
    Property(checkpointParameter => checkpointParameter.CriteriaSelectionId)
        .HasColumnName("CEC_ID");
}

但这给了我以下错误:

{“指定的架构无效。错误:\r\n(48,6):错误 0019:类型中的每个属性名称必须是唯一的。属性名称“CriteriaSelection_ID”已定义。”}

在不修改数据库的情况下,定义主键(即外键)的正确方法是什么?

【问题讨论】:

  • 您是否对生产数据副本中的这些列运行了不同的查询?听起来您确信这些键的组合形成了表的自然键。如果是,则继续在这些列上创建 SQL 主键。
  • 我确实有生产数据的副本,是的。我可以访问定义了表的 Oracle 数据库,其中包含以下内容(对我而言,这是关键):CREATE UNIQUE INDEX "X"."I$CEPOQ$UNIQUE" ON "X"."CEPOQ" ("CEC_ID", "CEPO_ID", "Q_ID", "FRQ"),其中 cec 是 Criteria,cepo 是 Ch.Operation,q 是参数。如果我错了,请纠正我
  • 在这个答案stackoverflow.com/a/15704189/2516770 中指出,Oracle 不认为唯一索引也是唯一约束或键约束。从第一条错误消息开始,我猜测创建唯一键约束将告诉 Oracle EF 提供程序它正在处理 (1:n) 关系的 1 侧的不同值。不过,这只是一个猜测。
  • @KeithPayne 这是一个很好的观点。但是,第二条消息告诉我,我不允许没有主键。我想我在 Stackoverflow 上的其他地方读到过,最好的解决方案是在数据库中添加主键。也许我应该重新审视一下故障排除路径。
  • @KeithPayne 仅供参考,我发现CREATE UNIQUE INDEX 不允许重复(由于UNIQUE 关键字)。所以它有点像主键(但它允许null 值)。

标签: c# entity-framework foreign-keys primary-key ef-database-first


【解决方案1】:

您需要在 Mapping 的 Criteria and Operation 中添加将作为参考的字段,如下所示:

this.HasKey(x => x.OperationId); // In Operation Mapping

this.HasKey(x => x.CriteriaId); // In Criteria Mapping

在 Criteria or Operation 中,您应该像这样映射一些:

this.HasMany(b => b.Criterias)
    .WithMany( x=> x.Operations)
    .Map(x =>
    {
        x.ToTable("CheckpointParameter");
        x.MapLeftKey("CriteriaId");
        x.MapRightKey("OperationId");
    });

【讨论】:

  • hm.. 但他们没有很多,是吗?我的意思是,CheckpointOperation 有很多 CheckpointParameters。 CheckpointParameter 知道 one CriteriaSelectionone Parameter。你能解释一下为什么我应该使用WithMany吗?
  • 你能用类图解释模型吗?
  • 我做了一些进一步的调试,看来我确实需要按照你的建议使用WithMany。我还注意到使用HasForeignKeyMap 效果更好,因为(我猜)它不必加载另一列,而只需加载外键 id 属性。
猜你喜欢
  • 2017-03-10
  • 1970-01-01
  • 2012-05-20
  • 1970-01-01
  • 1970-01-01
  • 2012-06-29
  • 2014-04-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多