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

时间:2014-01-30 13:17:26

标签: c# entity-framework 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<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测量列表。

1 个答案:

答案 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 /导航道具,但你知道如何做到这一点):

entity splitting result

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