Reputation: 5762
I want inherited classes from channel to share same foreign key, merging Gateway_GatewayId and Gateway_GatewayId1 columns into GatewayId column.
Can it be done?
I have tried this:
modelBuilder.Entity<ChannelModbus>().HasRequired(d => d.Gateway).WithMany()
.HasForeignKey(d => d.GatewayId).WillCascadeOnDelete(false)
But get this error:
The foreign key component 'GatewayId' is not a declared property on type 'ChannelModbus'. Verify that it has not been explicitly excluded from the model and that it is a valid primitive property.
And I've tried to use MapKey too:
modelBuilder.Entity<ChannelModbus>().HasRequired(d => d.Gateway).WithMany()
.Map(d => d.MapKey("GatewayId")).WillCascadeOnDelete(false);
And get this error:
One or more validation errors were detected during model generation:
GatewayId: Name: Each property name in a type must be unique. Property name 'GatewayId' is already defined.
GatewayId: Name: Each property name in a type must be unique. Property name 'GatewayId' is already defined.
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);
}
}
Upvotes: 1
Views: 1771
Reputation: 14640
Yes, it's possible. Just move the Gateway
property from ChannelModbus
and ChannelXmlRpc
to the base class, Channel
.
public abstract class Channel
{
public int ChannelId { get; private set; }
public int GatewayId { get; set; }
public virtual GatewayModbus Gateway { get; set; }
}
When you define the property on each derived class, since you use TPH inheritance, all columns will be mapped to a single table, one column belongs to ChannelModbus
and one column belongs to ChannelXmlRpc
even though they refer to the same entity. By moving it to the base class, both derived class will use the same column for foreign key.
Upvotes: 2