如何在添加其他关系时让双向关系不在双方创建外键?

时间:2015-05-24 09:28:11

标签: c# entity-framework

我正在尝试使用代码优先实体框架,在名为SectorShip的两个类之间建立简单的双向关系。这里的想法是Sector可以有0到多Ships,其中Ship始终有Sector,它是当前位置。

出于导航目的,我想在关系的两边都有一个属性。因此,类Sector包含ICollection<Ship>类型的属性,其中Ship包含Sector类型的属性。

Sector的主键是XY的组合。

public class Ship
{
    public int ID { get; set; }
    public string Name { get; set; }
    public double Speed { get; set; }

    public virtual Sector Sector { get; set; }
    //public virtual Sector Destination { get; set; }
}

public class Sector
{
    public Int64 X { get; set; }
    public Int64 Y { get; set; }

    public virtual ICollection<Ship> Ships { get; set; }
}

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

        // combined key for sector
        modelBuilder.Entity<Sector>()
            .HasKey(s => new { s.X, s.Y });
    }

表中的结果:

Sector
 - X
 - Y
Ship
 - ID
 - Name
 - Speed
 - Sector_X
 - Sector_Y

问题在于,只要我在ShipSector之间建立另一种关系,即它是Destination,就会在双方使用外键创建前面提到的关系。首先,我想知道为什么,其次如何防止它出现问题?我没有看到需要,并且导致第一个关系无法从双方导航,因为Sector_XSector_YNULLSector_X1和{{1是Sector_Y1。代表同样的事情。

NULL

2 个答案:

答案 0 :(得分:1)

添加Destination媒体资源时,您还需要在Sector班级IncomingShips上添加导航集。或者不要在Sector类上添加任何导航集。

我假设EF在ShipSector有2个导航属性但在Ship中只有一个Sector集合时会感到困惑,因此它会继续创建3 FK对

使用:

public class Ship {
    public int ID { get; set; }
    public string Name { get; set; }
    public double Speed { get; set; }

    public virtual Sector Sector { get; set; }
    public virtual Sector Destination { get; set; }
}

public class Sector {
    public Int64 X { get; set; }
    public Int64 Y { get; set; }
}

- 或 -

public class Ship {
    public int ID { get; set; }
    public string Name { get; set; }
    public double Speed { get; set; }

    public virtual Sector Sector { get; set; }
    public virtual Sector Destination { get; set; }
}

public class Sector {
    public Int64 X { get; set; }
    public Int64 Y { get; set; }

    public virtual ICollection<Ship> Ships { get; set; }
    public virtual ICollection<Ship> IncomingShips { get; set; }
}

protected override void OnModelCreating(DbModelBuilder modelBuilder) {
    .....
    modelBuilder.Entity<Sector>()
                .HasMany(p => p.Ships)
                .WithRequired(p => p.Sector)
                .WillCascadeOnDelete(false);

    modelBuilder.Entity<Sector>()
                .HasMany(p => p.IncomingShips)
                .WithRequired(p => p.Destination)
                .WillCascadeOnDelete(false);
}

两者都应该产生表格:

Sector
 - X
 - Y
Ship
 - ID
 - Name
 - Speed
 - Sector_X
 - Sector_Y
 - Destination_X
 - Destination_Y

答案 1 :(得分:0)

如果你看下&#34;关系公约&#34;在Code First Conventions,它说

  

如果相同类型之间存在多个关系(例如,假设您定义Person和Book类,其中Person类包含CommentsBooks和AuthoredBooks导航属性,而Book类包含Author和Reviewer导航属性),则需要通过使用Data Annotations或流畅的API手动配置关系。

由于componentWillReceivePropsShip之间存在多个关系,因此EF无法确定Sector上哪个导航属性与Ship上的集合属性相反,并创建了Sector的单独关系。

您需要使用Data Annotations(此处为一个示例,但还有其他方法可以执行此操作):

Sector.Ships

Fluent API

public class Sector
{
    public Int64 X { get; set; }
    public Int64 Y { get; set; }

    [InverseProperty("Sector")] 
    public virtual ICollection<Ship> Ships { get; set; }
}

由于protected override void OnModelCreating(DbModelBuilder modelBuilder) { // other stuff... modelBuilder.Entity<Ship>() .HasRequired(p => p.Sector) .WithMany(p => p.Ships); modelBuilder.Entity<Ship>() .HasRequired(p => p.Destination) .WithMany() .WillCascadeOnDelete(); } Sector有多个1:多关系,因此您可能必须使用Fluent API,因为您需要将至少一个关系设置为默认情况下不级联删除(或将Ship设置为可选?)或者您将获得&#34;多个级联路径&#34;错误。