实体框架在基类中共享外键

时间:2014-08-30 11:29:05

标签: c# entity-framework

问题

我希望通道中的继承类共享相同的外键,将Gateway_GatewayId和Gateway_GatewayId1列合并到GatewayId列中。

可以吗?

enter image description here

我试过这个:

modelBuilder.Entity<ChannelModbus>().HasRequired(d => d.Gateway).WithMany()
            .HasForeignKey(d => d.GatewayId).WillCascadeOnDelete(false)

但是得到这个错误:

  

外键组件“GatewayId”不是声明的属性   输入'ChannelModbus'。验证是否未明确排除它   来自模型,它是一个有效的原始属性。

我也尝试过使用MapKey:

modelBuilder.Entity<ChannelModbus>().HasRequired(d => d.Gateway).WithMany()
            .Map(d => d.MapKey("GatewayId")).WillCascadeOnDelete(false);

并收到此错误:

  

在模型生成期间检测到一个或多个验证错误:

     

GatewayId:名称:类型中的每个属性名称必须是唯一的。已定义属性名称“GatewayId”。

     

GatewayId:名称:类型中的每个属性名称必须是唯一的。已定义属性名称“GatewayId”。

代码

public abstract class Channel
{
    public int ChannelId { get; private set; }
    public int GatewayId { get; set; }
}

public abstract class Gateway
{
    public int GatewayId { get; private set; }
}

public abstract class GatewayTcp : Gateway
{
    public string Ip { get; set; }
    public int Puerto { get; set; }
}

public class GatewayModbus : GatewayTcp { }
public class GatewayXmlRpc : GatewayTcp { }

public class ChannelModbus : Channel
{
    public virtual GatewayModbus Gateway { get; set; }
}

public class ChannelXmlRpc : Channel
{
    public virtual GatewayXmlRpc Gateway { get; set; }
}

public partial class MyDbContext : DbContext
{
    public IDbSet<Channel> Channels { get; set; }
    public IDbSet<Gateway> Gateways { get; set; }

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

        modelBuilder.Entity<Gateway>().Property(d => d.GatewayId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        modelBuilder.Entity<Gateway>().HasKey(d => d.GatewayId);

        modelBuilder.Entity<Channel>().Property(d => d.ChannelId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        modelBuilder.Entity<Channel>().HasKey(d => d.ChannelId);

        modelBuilder.Entity<ChannelModbus>().HasRequired(d => d.Gateway).WithMany().WillCascadeOnDelete(false);
        modelBuilder.Entity<ChannelXmlRpc>().HasRequired(d => d.Gateway).WithMany().WillCascadeOnDelete(false);

        //modelBuilder.Entity<ChannelModbus>().HasRequired(d => d.Gateway).WithMany().HasForeignKey(d => d.GatewayId).WillCascadeOnDelete(false);
        //modelBuilder.Entity<ChannelXmlRpc>().HasRequired(d => d.Gateway).WithMany().HasForeignKey(d => d.GatewayId).WillCascadeOnDelete(false);
    }
}

1 个答案:

答案 0 :(得分:2)

是的,这是可能的。只需将Gateway属性从ChannelModbusChannelXmlRpc移至基类Channel

public abstract class Channel
{
    public int ChannelId { get; private set; }
    public int GatewayId { get; set; }
    public virtual GatewayModbus Gateway { get; set; }
}

当您在每个派生类上定义属性时,由于您使用TPH继承,因此所有列都将映射到单个表,一列属于ChannelModbus,一列属于ChannelXmlRpc,即使他们指的是同一个实体。通过将其移动到基类,两个派生类将使用相同的列作为外键。