【问题标题】:EF Code First on existing database, mapping one to manyEF Code First 在现有数据库上,一对多映射
【发布时间】:2014-02-01 04:07:00
【问题描述】:

我有一个由我无法修改的应用程序生成的数据库(我可以添加表、视图等,但我不能修改现有表,向它们添加列)。我在一个 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 中没有任何对应的行。

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

【问题讨论】:

    标签: c# entity-framework ef-code-first


    【解决方案1】:

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

    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 );
    

    这是 DB 中的结果(请注意,我没有为 Device 设置 FK/nav 道具,但你知道该怎么做):

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

    【讨论】:

    • 感谢您的意见。我尝试过表拆分方法,但它有一个问题。因为 EF 使用 INNER JOINMeasurement 没有指定其父级,这意味着在 Measurement_Parent 表中没有相应的行,虽然对我来说这种情况是有效的,因为测量的父字段是可选的。
    • 您只需为每个Measure 行创建一个Measure_Parent 记录,并将Parent ID 值设置为空
    猜你喜欢
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多