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,但实体拆分似乎不可能。 无论如何,这正是您正在寻找的 – 在不修改初始基础表的情况下扩展实体。