C# 通过 Fluent API 首先在 EF 代码中实现零或一到零或一的关系

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14701378/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 12:43:40  来源:igfitidea点击:

Implementing Zero Or One to Zero Or One relationship in EF Code first by Fluent API

c#entity-frameworkef-code-firstentity-relationshipfluent

提问by Masoud

I have two POCO classes

我有两个 POCO 课程

public class Order
{
    int id;
    string code;
    int? quotationId;  //it is foreign key
    public int Id{get;set;}
    public string Code{get;set;}
    public int? QuotationId{get;set;}
    Quotation quotation;
    public virtual Quotation Quotation { get; set; }
    ....
}

public class Quotation
{
    int Id;
    string Code;
    public int Id{get;set;}
    public string Code{get;set;}
    Order order;
    public virtual Order Order { get; set; }
    ....   
}

each Order may made from one or zero quotation, and each quotation maycause an order, so I have an "one or zero" to "one or zero" relation, how can I implement this, in EF Code first by fluent API?

每个订单可能由一个或零个报价构成,每个报价都可能导致一个订单,所以我有一个“一或零”到“一或零”的关系,我如何在 EF Code 中首先通过 fluent API 实现这一点?

采纳答案by Masoud

By changing pocos to:

通过将 pocos 更改为:

public class Order
{
    public int OrderId { get; set; }
    public virtual Quotation Quotation { get; set; }
}
public class Quotation
{
    public int QuotationId { get; set; }
    public virtual Order Order { get; set; }
}

and using these mapping files:

并使用这些映射文件:

public class OrderMap : EntityTypeConfiguration<Order>
{
    public OrderMap()
    {
        this.HasOptional(x => x.Quotation)
            .WithOptionalPrincipal()
            .Map(x => x.MapKey("OrderId"));
    }
}

public class QuotationMap : EntityTypeConfiguration<Quotation>
{
    public QuotationMap()
    {
        this.HasOptional(x => x.Order)
            .WithOptionalPrincipal()
            .Map(x => x.MapKey("QuotationId"));
    }
}

we will have this DB(that means 0..1-0..1):

我们将拥有这个 DB(这意味着 0..1-0..1):

enter image description here

在此处输入图片说明

with special thanks to (Mr. Vahid Nasiri)

特别感谢 ( Vahid Nasiri 先生)

回答by Moritz

Adapted from this answer, try this.

改编自这个答案,试试这个。

First, fix your classes:

首先,修复您的课程:

public class Order
{
  public int Id {get; set;}
  public virtual Quotation Quotation { get; set; }
  // other properties
}

public class Quotation
{
  public int Id {get; set;}
  public virtual Order Order { get; set; }
  // other properties
}

Then use the fluent API like that:

然后像这样使用流畅的 API:

modelBuilder.Entity<Quotation>()
.HasOptional(quote => quote.Order)
.WithRequired(order=> order.Quotation);

Basically, for 1:1 or [0/1]:[0/1] relationships, EF needs the primary keys to be shared.

基本上,对于 1:1 或 [0/1]:[0/1] 关系,EF 需要共享主键。

回答by phil soady

See http://msdn.microsoft.com/en-us/data/jj591620EF Relationships

请参阅http://msdn.microsoft.com/en-us/data/jj591620EF 关系

An excellent Book http://my.safaribooksonline.com/book/-/9781449317867

一本优秀的书 http://my.safaribooksonline.com/book/-/9781449317867

Here is a post from developer from Dec 2010. But still relevant http://social.msdn.microsoft.com/Forums/uk/adonetefx/thread/aed3b3f5-c150-4131-a686-1bf547a68804The above article is a nice summary or the possible combinations here.

这是 2010 年 12 月开发人员的帖子。但仍然相关 http://social.msdn.microsoft.com/Forums/uk/adonetefx/thread/aed3b3f5-c150-4131-a686-1bf547a68804以上文章是一个很好的总结或这里可能的组合。

A solution where dependant Table has key from Primary table is possible.

依赖表具有主表中的键的解决方案是可能的。

If you Want Independent Keys where both are Principals in a PK/FK scenario, i dont think you can do it in Code first with Fluent API. If they share a Key, You are OK. 1:1 optional assumes the dependent uses the key from Primary.

如果您想要在 PK/FK 场景中两者都是主体的独立密钥,我认为您无法使用 Fluent API 在 Code first 中做到这一点。如果他们共享一个密钥,你就可以了。1:1 可选假设依赖使用来自主要的密钥。

But since you need to save one of the tables before the other. You can check one of the Foreign Keys with code. OR add teh second Foreign to Database after Code first has created it.

但是因为您需要先保存其中一个表。您可以使用代码检查其中一个外键。或者在 Code first 创建之后将第二个 Foreign 添加到数据库中。

You will get close. But EF will complain about conflicting Foreign keys if you want both to be Foreign keys. Essentially the A depends on B depends A EF doesnt like, even if the columns are nullable and technically possible on the DB.

你会靠近。但是如果您希望两者都是外键,EF 会抱怨外键冲突。本质上 A 取决于 B 取决于 A EF 不喜欢,即使列可以为空并且在 DB 上在技术上是可行的。

Here use this test program to try it. Just comment in an out the Fluent API stuff to try some options. I could NOT get EF5.0 to work with INDEPENDENT PK/FK 0:1 to 0:1But of course there are reasonable compromises as discussed.

这里用这个测试程序来试试。只需在 Fluent API 内容中发表评论即可尝试一些选项。 我无法让 EF5.0 与 INDEPENDENT PK/FK 0:1 到 0:1 一起工作,但当然有讨论的合理妥协。

using System.Data.Entity;
using System.Linq;
namespace EF_DEMO
{
class Program
{
    static void Main(string[] args) {
        var ctx = new DemoContext();
        var ord =  ctx.Orders.FirstOrDefault();
        //. DB should be there now...
    }
}
public class Order
{
public int Id {get;set;}
public string Code {get;set;}
public int? QuotationId { get; set; }   //optional  since it is nullable
public virtual Quotation Quotation { get; set; }
  //....
}
public class Quotation
{
 public int Id {get;set;}
 public string Code{get;set;}
// public int? OrderId { get; set; }   //optional  since it is nullable
 public virtual Order Order { get; set; }
 //...
}
public class DemoContext : DbContext
{
    static DemoContext()
    {
    Database.SetInitializer(new DropCreateDatabaseIfModelChanges<DemoContext>());
    }
    public DemoContext()
        : base("Name=Demo") { }
    public DbSet<Order> Orders { get; set; }
    public DbSet<Quotation> Quotations { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
       modelBuilder.Entity<Order>().HasKey(t => t.Id)
                    .HasOptional(t => t.Quotation)
                    .WithOptionalPrincipal(d => d.Order)
                    .Map(t => t.MapKey("OrderId"));  // declaring here  via MAP means NOT declared in POCO
        modelBuilder.Entity<Quotation>().HasKey(t => t.Id)
                    .HasOptional(q => q.Order)
            // .WithOptionalPrincipal(p => p.Quotation)  //as both Principals
            //        .WithOptionalDependent(p => p.Quotation) // as the dependent
            //         .Map(t => t.MapKey("QuotationId"));    done in POCO.
            ;
    }   
}
}

回答by Kenneth Bo Christensen

@Masoud's procedure was:

@Masoud 的程序是:

modelBuilder.Entity<Order>()
            .HasOptional(o => o.Quotation)
            .WithOptionalPrincipal()
            .Map(o => o.MapKey("OrderId"));

modelBuilder.Entity<Quotation>()
            .HasOptional(o => o.Order)
            .WithOptionalPrincipal()
            .Map(o => o.MapKey("QuotationId"));

It gives:

它给:

enter image description here

在此处输入图片说明

By changing the code to:

通过将代码更改为:

modelBuilder.Entity<Order>()
            .HasOptional(o => o.Quotation)
            .WithOptionalPrincipal(o=> o.Order);

It gives:

它给:

enter image description here

在此处输入图片说明

回答by astro8891

public class OfficeAssignment
{
    [Key]
    [ForeignKey("Instructor")]
    public int InstructorID { get; set; }
    [StringLength(50)]
    [Display(Name = "Office Location")]
    public string Location { get; set; }

    public virtual Instructor Instructor { get; set; }
}

The Key Attribute

There's a one-to-zero-or-one relationship between the Instructor and the OfficeAssignment entities. An office assignment only exists in relation to the instructor it's assigned to, and therefore its primary key is also its foreign key to the Instructor entity. But the Entity Framework can't automatically recognize InstructorID as the primary key of this entity because its name doesn't follow the ID or classnameID naming convention. Therefore, the Key attribute is used to identify it as the key:

public class OfficeAssignment
{
    [Key]
    [ForeignKey("Instructor")]
    public int InstructorID { get; set; }
    [StringLength(50)]
    [Display(Name = "Office Location")]
    public string Location { get; set; }

    public virtual Instructor Instructor { get; set; }
}

关键属性

Instructor 和 OfficeAssignment 实体之间存在一对零或一的关系。办公室分配仅与分配给它的讲师相关,因此其主键也是其对 Instructor 实体的外键。但是实体框架无法自动将 InstructorID 识别为该实体的主键,因为其名称不遵循 ID 或 classnameID 命名约定。因此,Key 属性用于将其标识为密钥:

https://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-a-more-complex-data-model-for-an-asp-net-mvc-application

https://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-a-more-complex-data-model-for-an-asp-net- mvc-应用程序

回答by Mohammad Reza Sadreddini

using DataAnnotations:

使用数据注释:

public class Order
{
       [Key]
       public int Id {get; set;}

       public virtual Quotation Quotation { get; set; }
}

public class Quotation
{
     [Key, ForeignKey(nameof(Order))]
     public int Id {get; set;}

     public virtual Order Order { get; set; }
}