我有一个由应用程序生成的数据库,我无法修改(我可以添加表,视图等但我无法修改现有表,向它们添加列)。我在一个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<Measurement>();
}
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<Measurement> 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
测量列表。
答案 0 :(得分:2)
您需要的是实体拆分 - 在两个或多个表之间拆分单个实体。这隐含地涉及共享主键 - 在这种情况下,关系表中的共享键将是子实体的ID。您可以通过调用多个Map
方法来执行此操作,每个方法都调用EntityMappingConfiguration.Properties
来定义应该包含在该映射片段中的属性以及调用ToTable
来设置表名。< / p>
modelBuilder.Entity<Measurement>()
.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<Measurement>()
.HasOptional( npe => npe.Parent )
.WithMany( npe => npe.Children )
.HasForeignKey( fke => fke.ParentId );
以下是数据库中的结果(注意我没有为Device
设置FK /导航道具,但你知道如何做到这一点):
理想情况下,Parent_MeasurementId
字段将为not null
并删除记录,而不是将该列设置为null(如果它们不是父列),但实际拆分似乎不可能。无论如何,这正是您正在寻找的 - 在不修改初始基础表的情况下扩展实体。