EF Code First在现有数据库上,映射一对多

我有一个由应用程序生成的数据库,我无法修改(我可以添加表,视图等,但我无法修改现有的表,向它们添加列)。 我在一个Web应用程序上工作,该应用程序使用BreezeJS允许Web应用程序的客户端部分通过OData协议查询数据。

Measurement表具有以下结构:

 MeasurementId INT DeviceId INT FOREIGN KEY REFERENCES Devices (DeviceId) Name VARCHAR, PRIMARY KEY (MeasurementId) 

我需要的是添加可空的ParentId自引用外键,因为我无法修改现有的表,我创建了一个新的, Measurement_Parent

 MeasurementId INT FOREIGN KEY REFERENCES Measurements (MeasurementId), ParentId INT FOREIGN KEY REFERENCES Measurements (MeasurementId), PRIMARY KEY (MeasurementId) 

我有以下实体:

 public partial class Measurement { public Measurement() { this.Children = new List(); } public Int32 MeasurementId { get; set; } public virtual Measurement Parent { get; set; } public Int32 DeviceId { get; set; } public virtual Device Device { get; set; } public String Name { get; set; } public virtual ICollection Children { get; set; } } 

现在是棘手的部分。 我已经尝试了许多不同的方法来实现这一目标,但没有成功。 我的实体的当前EntityTypeConfiguration如下所示:

 // Primary Key this.HasKey(m => m.MeasurementId); // Table & Column Mappings this.Property(t => t.MeasurementId) .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None); // Table & Column Mappings this.ToTable("Measurement"); this.Property(m => m.MeasurementId); this.Property(m => m.DeviceId); this.Property(m => m.Name); // Relationships // Each measurement references device performing the measurement. this.HasRequired(d => d.Device) .WithMany(m => m.Measurements) .HasForeignKey(d => d.DeviceId); // Each measurement can have optional parent. this.HasOptional(measurement => measurement.Parent) .WithMany() // .WithMany(measurement => measurement.Children) ?? .Map(m => { m.MapKey("ParentId"); m.ToTable("Measurement_Parent"); }); 

不幸的是,这在加载我的应用时给了我奇怪的错误:

 Metadata query failed for: api/EDW/Metadata; The specified table 'Measurement_Parent' was not found in the model. Ensure that the table name has been correctly specified. 

我不知道为什么会这样,因为桌子在那里。 我尝试将这两个表映射到一个实体(表拆分),但因为ParentId可以为NULL而EF为此映射生成INNER JOIN而不是LEFT OUTER JOIN ,所以它不起作用,因为Measurement表中的某些行被省略了在Measurement_Parent没有任何相应的行。

基本上我需要的是具有可选的Parent属性,参考父测量和Children测量列表。

您需要的是实体拆分 – 在两个或多个表之间拆分单个实体。 这隐含地涉及共享主键 – 在这种情况下,关系表中的共享键将是子实体的ID。 您可以通过调用多个Map方法来完成此操作,每个方法都调用EntityMappingConfiguration.Properties来定义应该在该映射片段中包含哪些属性以及调用ToTable来设置表名。

 modelBuilder.Entity() .HasKey( ke => ke.MeasurementId ) .Map( emc => { emc.Properties( pe => new { pe.MeasurementId, pe.Name, pe.DeviceId } ); emc.ToTable( "Measurement" ); } ) .Map( emc => { emc.Properties( pe => new { pe.MeasurementId, pe.ParentId } ); // maybe name this MeasurementExtension? This table could // be used for any properties you wish to add to the Measurement entity emc.ToTable( "Measurement_Parent" ); // for this example's clarity I've named the PK Child_MeasurementId // but in real-world use I would name it MeasurementId emc.Property( pe => pe.MeasurementId ).HasColumnName( "Child_MeasurementId" ); emc.Property( pe => pe.ParentId ).HasColumnName( "Parent_MeasurementId" ); } ); modelBuilder.Entity() .HasOptional( npe => npe.Parent ) .WithMany( npe => npe.Children ) .HasForeignKey( fke => fke.ParentId ); 

这是DB中的结果(注意我没有为Device设置FK / nav道具,但你知道如何做到这一点):

实体拆分结果

理想情况下, Parent_MeasurementId字段not null为null,如果它们不是父级,则删除记录而不是将该列设置为null,但实体拆分似乎不可能。 无论如何,这正是您正在寻找的 – 在不修改初始基础表的情况下扩展实体。