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

别来无恙 提交于 2020-01-26 08:46:35

问题


I have two POCO classes

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 may cause 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?


回答1:


By changing pocos to:

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):

with special thanks to (Mr. Vahid Nasiri)




回答2:


@Masoud's procedure was:

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:

By changing the code to:

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

It gives:




回答3:


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

An excellent Book 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-1bf547a68804 The above article is a nice summary or the possible combinations here.

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.

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.

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.

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:1 But of course there are reasonable compromises as discussed.

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.
            ;
    }   
}
}



回答4:


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:

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.




回答5:


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:

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://stackoverflow.com/questions/14701378/implementing-zero-or-one-to-zero-or-one-relationship-in-ef-code-first-by-fluent

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!