ChatGPT解决这个技术问题 Extra ChatGPT

我应该如何在 MVC3 中使用 Code First Entity Framework (4.1) 声明外键关系?

我一直在寻找有关如何使用代码优先 EF 4.1 声明外键关系和其他约束的资源,但运气不佳。基本上我在代码中构建数据模型并使用 MVC3 来查询该模型。一切都通过 MVC 工作,这很棒(向微软致敬!)但现在我不希望它工作,因为我需要有数据模型约束。

例如,我有一个 Order 对象,它有大量的外部对象(表)属性。现在我可以创建一个 Order 没问题,但不能添加外键或外部对象。 MVC3 设置这个没有问题。

我意识到我可以在保存之前自己在控制器类中添加对象,但是如果没有满足约束关系,我希望对 DbContext.SaveChanges() 的调用失败。

新信息因此,特别是,当我尝试保存 Order 对象而不指定客户对象时,我希望发生异常。如果我只是按照大多数 Code First EF 文档中的描述来组合对象,这似乎不是行为。

最新代码:

public class Order
{
    public int Id { get; set; }

    [ForeignKey( "Parent" )]
    public Patient Patient { get; set; }

    [ForeignKey("CertificationPeriod")]
    public CertificationPeriod CertificationPeriod { get; set; }

    [ForeignKey("Agency")]
    public Agency Agency { get; set; }

    [ForeignKey("Diagnosis")]
    public Diagnosis PrimaryDiagnosis { get; set; }

    [ForeignKey("OrderApprovalStatus")]
    public OrderApprovalStatus ApprovalStatus { get; set; }

    [ForeignKey("User")]
    public User User { get; set; }

    [ForeignKey("User")]
    public User Submitter { get; set; }

    public DateTime ApprovalDate { get; set; }
    public DateTime SubmittedDate { get; set; }
    public Boolean IsDeprecated { get; set; }
}

这是我现在在访问 VS 生成的 Patient 视图时遇到的错误:

错误消息“PhysicianPortal.Models.Order”类型的属性“Patient”上的 ForeignKeyAttribute 无效。在依赖类型“PhysicianPortal.Models.Order”上找不到外键名称“Parent”。 Name 值应该是逗号分隔的外键属性名称列表。

问候,

圭多


S
Sergi Papaseit

如果您有一个 Order 类,则添加一个引用模型中另一个类的属性,例如 Customer 应该足以让 EF 知道其中存在关系:

public class Order
{
    public int ID { get; set; }

    // Some other properties

    // Foreign key to customer
    public virtual Customer Customer { get; set; }
}

您始终可以明确设置 FK 关系:

public class Order
{
    public int ID { get; set; }

    // Some other properties

    // Foreign key to customer
    [ForeignKey("Customer")]
    public string CustomerID { get; set; }
    public virtual Customer Customer { get; set; }
}

ForeignKeyAttribute 构造函数将字符串作为参数:如果将其放在外键属性上,则它表示关联导航属性的名称。如果将它放在导航属性上,它代表关联外键的名称。

这意味着,如果您将 ForeignKeyAttribute 放在 Customer 属性的哪个位置,则该属性将在构造函数中采用 CustomerID

public string CustomerID { get; set; }
[ForeignKey("CustomerID")]
public virtual Customer Customer { get; set; }

EDIT based on Latest Code 由于这一行,您会收到该错误:

[ForeignKey("Parent")]
public Patient Patient { get; set; }

EF 将查找名为 Parent 的属性以将其用作外键强制执行器。你可以做两件事:

1) 删除 ForeignKeyAttribute 并将其替换为 RequiredAttribute 以根据需要标记关系:

[Required]
public virtual Patient Patient { get; set; }

RequiredAttribute 装饰属性还有一个很好的副作用:数据库中的关系是用 ON DELETE CASCADE 创建的。

我还建议设置属性 virtual 以启用延迟加载。

2) 创建一个名为 Parent 的属性,用作外键。在这种情况下,将其称为 ParentID 可能更有意义(您还需要更改 ForeignKeyAttribute 中的名称):

public int ParentID { get; set; }

以我在这种情况下的经验,尽管以相反的方式使用它会更好:

[ForeignKey("Patient")]
public int ParentID { get; set; }

public virtual Patient Patient { get; set; }

谢谢 Sergi - 我在块引用中添加了一些额外的信息。
@Guido - 我已经根据您最新的代码编辑更新了我的答案,希望这会有所帮助。
L
Leon Bambrick

您可以通过以下方式定义外键:

public class Parent
{
   public int Id { get; set; }
   public virtual ICollection<Child> Childs { get; set; }
}

public class Child
{
   public int Id { get; set; }
   // This will be recognized as FK by NavigationPropertyNameForeignKeyDiscoveryConvention
   public int ParentId { get; set; } 
   public virtual Parent Parent { get; set; }
}

现在 ParentId 是外键属性,定义了孩子和现有父母之间的必要关系。在没有现有父母的情况下保存孩子将引发异常。

如果您的 FK 属性名称不包含导航属性名称和父 PK 名称,您必须使用 ForeignKeyAttribute 数据注释或流式 API 来映射关系

数据注释:

// The name of related navigation property
[ForeignKey("Parent")]
public int ParentId { get; set; }

流畅的 API:

modelBuilder.Entity<Child>()
            .HasRequired(c => c.Parent)
            .WithMany(p => p.Childs)
            .HasForeignKey(c => c.ParentId);

data annotations and model validation 可以强制执行其他类型的约束。

编辑:

如果您不设置 ParentId,您将得到一个例外。它是必需的属性(不可为空)。如果您只是不设置它,它很可能会尝试将默认值发送到数据库。默认值为 0,因此如果您没有 Id = 0 的客户,您将收到异常。


谢谢 Ladislav - 我在块引用中添加了一些附加信息。
@拉迪斯拉夫。因此,为了强制执行此约束,我必须同时拥有对 Parent 的引用和对 ParentId 的引用。那是对的吗?我将添加上面的实际类以供参考。
@Guido:这是新信息。您没有使用外键属性。默认情况下,您的所有导航属性都作为可选属性处理。根据需要使用流利的映射来映射它们。
@Ladislav:再次感谢您。我正在环顾四周以了解使用数据注释和 Fluent API 之间的区别。我根据我认为您所说的对上面的代码进行了更改。以上是我必须做的吗?问候。
没有 ForeignKey 属性定义与外键属性相关的导航属性,反之亦然。您没有外键属性,因此您不能使用该属性。尝试在导航属性上使用 Required 属性(我没有测试过)。