【问题标题】:one to zero or one relationship in entity framework实体框架中的一对零或一对关系
【发布时间】:2017-01-06 09:26:18
【问题描述】:

我有 2 个标准实体:

组:

[Table("CONTROL_GROUP", Schema = "CONTROL")]
public partial class Group
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Required]
    [Column("ID")]
    public decimal Id { get; set; }

    [Required]
    [Column("NAME")]
    [MaxLength(200)]
    public string Name { get; set; }

    public virtual GroupMetier GroupMetier { get; set; }
}

GroupMetier:

[Table("CONTROL_GROUP_METIER", Schema = "CONTROL")]
public partial class GroupMetier
{
    [Key]
    [Required]
    [Column("GROUP_ID")]
    public int GroupId { get; set; }

    [Required]
    [Column("NAME")]
    [MaxLength(200)]
    public string Name { get; set; }

    public virtual Group Group { get; set; }
}

在我的模型构建器中,我将 relashionship 定义如下:

// GroupMetier 0..1 <-> 1 Group
modelBuilder.Entity<GroupMetier>()
    .HasRequired<Group>(gm => gm.Group)
    .WithOptional(g => g.GroupMetier)

但是,在执行时,当我尝试使用此 linq 检索组时:

_context.Groups.Where(item => item.GroupMetier != null)

生成的sql执行失败:

SELECT 
    "Extent3"."GROUP_ID" AS "GROUP_ID", 
    "Extent1"."ID" AS "ID", 
    "Extent1"."NAME" AS "NAME", 
    "Extent2"."GROUP_ID" AS "GROUP_ID1"
FROM   "CONTROL"."CONTROL_GROUP" "Extent1"
    LEFT OUTER JOIN "CONTROL"."CONTROL_GROUP_METIER" "Extent2" ON "Extent1"."ID" = "Extent2"."GroupId"
    INNER JOIN "CONTROL"."CONTROL_GROUP_METIER" "Extent3" ON "Extent1"."ID" = "Extent3"."GroupId"
WHERE (1 = 1)

问题显然来自实体试图加入不存在的"Extent2"."GroupId" 列而不是正确的"Extent2"."GROUP_ID"

我是不是没有在某处声明什么东西才能让这种反感起作用?

编辑:根据要求,CONTROL.CONTROL_GROUP_METIER 表:

CREATE TABLE CONTROL.CONTROL_GROUP_METIER
(
  GROUP_ID  INTEGER                             NOT NULL,
  NAME      VARCHAR2(200 CHAR)                  NOT NULL
)
TABLESPACE CONTROL_DATA
RESULT_CACHE (MODE DEFAULT)
PCTUSED    0
PCTFREE    10
INITRANS   1
MAXTRANS   255
STORAGE    (
            INITIAL          64K
            NEXT             1M
            MAXSIZE          UNLIMITED
            MINEXTENTS       1
            MAXEXTENTS       UNLIMITED
            PCTINCREASE      0
            BUFFER_POOL      DEFAULT
            FLASH_CACHE      DEFAULT
            CELL_FLASH_CACHE DEFAULT
           )
LOGGING 
NOCOMPRESS 
NOCACHE
NOPARALLEL
MONITORING;


CREATE UNIQUE INDEX CONTROL.CONTROL_GROUP_METIER_PK ON CONTROL.CONTROL_GROUP_METIER
(GROUP_ID)
LOGGING
TABLESPACE CONTROL_DATA
PCTFREE    10
INITRANS   2
MAXTRANS   255
STORAGE    (
            INITIAL          64K
            NEXT             1M
            MAXSIZE          UNLIMITED
            MINEXTENTS       1
            MAXEXTENTS       UNLIMITED
            PCTINCREASE      0
            BUFFER_POOL      DEFAULT
            FLASH_CACHE      DEFAULT
            CELL_FLASH_CACHE DEFAULT
           )
NOPARALLEL;


ALTER TABLE CONTROL.CONTROL_GROUP_METIER ADD (
  CONSTRAINT CONTROL_GROUP_METIER_PK
  PRIMARY KEY
  (GROUP_ID)
  USING INDEX CONTROL.CONTROL_GROUP_METIER_PK
  ENABLE VALIDATE);

ALTER TABLE CONTROL.CONTROL_GROUP_METIER ADD (
  CONSTRAINT CONTROL_GROUP_METIER_R01 
  FOREIGN KEY (GROUP_ID) 
  REFERENCES CONTROL.CONTROL_GROUP (ID)
  ENABLE VALIDATE);

【问题讨论】:

  • 我不明白您为什么要使用流畅的 API 和数据注释?如果这是一个 Web 应用程序,您也可以使用其中之一,最好不要使用虚拟关键字
  • 我正在使用 fluent api 来定义其他所有内容的关系和数据注释。由于我的模型中有大约 130 个实体,因此我无法通过 fluent 定义所有内容,因为维护起来会很痛苦,并且由于未知原因,ForeignKey 数据注释似乎在我的模型中根本不起作用。我还必须使用虚拟来进行延迟加载,因为完全加载我的任何实体都会太长,当我只需要检查一个对象的属性时会加载数千个对象。
  • 你能显示CONTROL_GROUP_METIER 表吗?
  • 主要问题是您是否在 CONTROL_GROUP_METIER 表中有单独的 FK 列,或者 PK 也用作 FK(这似乎是不可能的,因为 GROUP_ID 列类型是 int 而 @987654334 @ 是 decimal)。
  • 所以您确实在尝试将PK用作FK。但是 EF 不允许在不同类型的列之间建立 FK 关系。为什么IDdecimal

标签: c# oracle entity-framework linq entity-framework-6


【解决方案1】:

我是不是没有在某处声明什么东西才能让这种反感起作用?

您的配置对于所谓的Shared Primary Key Association 来说很好,通常会产生这样的迁移(只是为了测试映射):

CreateTable(
    "CONTROL.CONTROL_GROUP_METIER",
    c => new
        {
            GROUP_ID = c.Int(nullable: false),
            NAME = c.String(nullable: false, maxLength: 200),
        })
    .PrimaryKey(t => t.GROUP_ID)
    .ForeignKey("CONTROL.CONTROL_GROUP", t => t.GROUP_ID)
    .Index(t => t.GROUP_ID);

然而,它实际上会产生这样的结果:

CreateTable(
    "CONTROL.CONTROL_GROUP_METIER",
    c => new
        {
            GROUP_ID = c.Int(nullable: false, identity: true),
            NAME = c.String(nullable: false, maxLength: 200),
            Group_Id = c.Decimal(nullable: false, precision: 18, scale: 2),
        })
    .PrimaryKey(t => t.GROUP_ID)
    .ForeignKey("CONTROL.CONTROL_GROUP", t => t.Group_Id)
    .Index(t => t.Group_Id);

如您所见,这不是您想要的。

这是为什么呢?为了更好地理解,让我们将显式的ForeignKey 属性应用于Group 属性:

[ForeignKey("GroupId")]
public virtual Group Group { get; set; }

现在迁移失败并出现以下错误:

GroupMetier_Group_Target_GroupMetier_Group_Source: : 引用约束的Dependent Role 中所有属性的类型必须与Principal Role 中对应的属性类型相同。实体“GroupMetier”上的属性“GroupId”类型与引用约束“GroupMetier_Group”中实体“Group”上的属性“Id”类型不匹配。

所以问题是Group.Id 属性类型是decimalGroupMetier.GroupId 属性类型是int,在这种情况下,EF 无法识别关系并尝试使用One-to-One Foreign Key Association,这当然不会t 匹配您的数据库模型。

如何解决?很难说,但您应该以某种方式将两个属性都设为intdecimal

【讨论】:

    【解决方案2】:

    您尝试过 ForeignKey 注释吗?

    [ForeignKey("GROUP_ID")]
    public virtual Group Group { get; set; }
    

    【讨论】:

    • @remy-grandin 然后检查是否在数据库中按预期创建了关联。
    • 我首先使用现有数据库模型编写代码,因此我的表和关系已经由我们的 dba 创建。此外,由于未知原因,ForeignKey 数据注释似乎不适用于我的模型
    【解决方案3】:

    在流畅的 API 中

    modelBuilder.Entity<GroupMetier>()
    .HasRequired<Group>(gm => gm.Group)
    .WithOptional(g => g.GroupMetier)
    .Map(g => g.MapKey("GROUP_ID"));
    

    【讨论】:

    • 它给了我一个模型验证异常:GROUP_ID: Name: Each property name in a type must be unique. Property name 'GROUP_ID' is already defined..
    • 你试过这个modelBuilder.Entity&lt;GroupMetier&gt;() .HasRequired&lt;Group&gt;(gm =&gt; gm.Group) .WithOptional(g =&gt; g.GroupMetier) .Map(g =&gt; g.MapKey("GROUP_ID")) .HasForeignKey(g =&gt; g.GroupId)
    猜你喜欢
    • 2015-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-18
    • 2016-12-16
    • 2020-01-31
    • 1970-01-01
    • 2016-07-19
    相关资源
    最近更新 更多