简体   繁体   English

EF代码第一个单向导航属性

[英]EF Code first one way navigation property

I have the following entities: 我有以下实体:

[KnownType(typeof(Script))]
public class Application : IEntity
{
    public long ID { get; set; }
    public string Name { get; set; }
    public long? StartScriptID { get; set; }
    // Other properties...

    // Navigation properties:
    public virtual Script StartScript { get; set; }   // new
    public virtual List<Script> Scripts { get; set; }
}

[KnownType(typeof(Application))]
public class Script : IEntity
{
    public long ID { get; set; }
    public string Name { get; set; }
    // Other properties...

    // Navigation properties:
    public virtual Application Application { get; set; }
}

I have no fluent configurations on the DbContext 我在DbContext上没有流畅的配置

So the model exists of Scripts which must be bound to an application. 因此,存在必须绑定到应用程序的脚本模型。 Applications can have a startScript defined. 应用程序可以定义一个startScript。 All this I already have working. 这一切我已经在工作了。

Now I am in need of a navigation property: Application.StartScript . 现在,我需要一个导航属性: Application.StartScript

The question is how can I add the navigation property on Application without having to add a the equivalent navigation property on Script . 问题是,如何在Application上添加导航属性, 不必在Script上添加等效的导航属性。

Thanks in advance! 提前致谢!



EDIT: When I run Add-Migration the following migration code is generated: 编辑:当我运行添加迁移时,将生成以下迁移代码:

public override void Up()
{
    DropForeignKey("dbo.Scripts", "ApplicationID", "dbo.Applications");
    AddColumn("dbo.Scripts", "Application_ID", c => c.Long());
    CreateIndex("dbo.Applications", "StartScriptID");
    CreateIndex("dbo.Scripts", "Application_ID");
    AddForeignKey("dbo.Applications", "StartScriptID", "dbo.Scripts", "ID");
    AddForeignKey("dbo.Scripts", "Application_ID", "dbo.Applications", "ID");
}

This creates a new column on Scripts which I don't need, as I already have the StartScriptID column. 这将在不需要的脚本上创建一个新列,因为我已经有了StartScriptID列。


EDIT: Update after @haim770 answer 编辑:@ haim770回答后更新

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Application>().HasOptional(x => x.StartScript).WithOptionalDependent(x => x.Application);
}

public override void Up()
{
    DropForeignKey("dbo.Scripts", "ApplicationID", "dbo.Applications");
    DropIndex("dbo.Scripts", new[] { "ApplicationID" });
    RenameColumn(table: "dbo.Applications", name: "ApplicationID", newName: "StartScript_ID");
    AddColumn("dbo.Scripts", "Application_ID", c => c.Long());
    CreateIndex("dbo.Applications", "StartScript_ID");
    CreateIndex("dbo.Scripts", "Application_ID");
    AddForeignKey("dbo.Scripts", "Application_ID", "dbo.Applications", "ID");
    AddForeignKey("dbo.Applications", "StartScript_ID", "dbo.Scripts", "ID");
}

It doesn't understand that it should use the already existing StartScriptID. 它不了解它应该使用已经存在的StartScriptID。 Is there a way to point it in the right direction? 有没有办法将其指向正确的方向?


EDIT: Wanted database structure: 编辑:想要的数据库结构:

Applications: 应用范围:

  • ID, PK, bigint, not null ID,PK,bigint,不为null
  • Name, nvarchar(max), not null 名称,nvarchar(max),不为null
  • StartScriptID, bigint, null StartScriptID,bigint,空

Scripts: 脚本:

  • ID, PK, bigint, not null ID,PK,bigint,不为null
  • Name, nvarchar(max), not null 名称,nvarchar(max),不为null
  • ApplicationID, FK, bigint, not null ApplicationID,FK,bigint,不为null


EDIT: 编辑:

public class Application
{
    [InverseProperty("StartScript")]
    public long? StartScriptID { get; set; }
    [ForeignKey("StartScriptID")]
    public virtual Script StartScript { get; set; }
}

I was thinking there was no changes needed in the database, so I have tried adding migration with -IgnoreChanges. 我以为数据库中不需要更改,因此我尝试使用-IgnoreChanges添加迁移。 But then I got an EntityCommandExecutionException when querying for entities: "Invalid column name 'Application_ID'". 但是然后在查询实体时出现了EntityCommandExecutionException :“无效的列名'Application_ID'”。 So the Entity Framework needs some configuration for telling to use the StartScriptID property. 因此,实体框架需要一些配置以告知使用StartScriptID属性。

You can modify the mapping using the ForeignKeyAttribute and the InversePropertyAttribute . 您可以使用ForeignKeyAttributeInversePropertyAttribute修改映射。 If that doesn't work the way you want, you can always edit the migration yourself before applying it. 如果那不能按照您想要的方式工作,则始终可以在应用迁移之前自行编辑迁移。

If you want to customize the column name, try the ColumnAttribute: 如果要自定义列名称,请尝试使用ColumnAttribute:

public class Application
{
    [Column("DatabaseColumnName")]
    public long? StartScriptID { get; set; }
    [ForeignKey("StartScriptID")]
    public virtual Script StartScript { get; set; }
}

A longer explanation can be found here: http://msdn.microsoft.com/de-de/data/gg193958.aspx 可以在这里找到更长的说明: http : //msdn.microsoft.com/de-de/data/gg193958.aspx

Try to use EntityTypeConfiguration It makes more easy to handle this kind of problem. 尝试使用EntityTypeConfiguration可以更轻松地处理此类问题。 Then: 然后:

public class Application 
{
    public long ID { get; set; }
    public string Name { get; set; }
    public long? StartScriptID { get; set; }
    // Other properties...

    // Navigation properties:
    public virtual Script StartScript { get; set; }   // new
    public virtual ICollection<Script> Scripts { get; set; }
}

public class Script 
{
    public long ID { get; set; }
    public string Name { get; set; }
    public int ApplicationId { get; set; }
    // Other properties...

    // Navigation properties:
    public virtual Application Application { get; set; }
}

public class ApplicationMap : EntityTypeConfiguration<Application>
{
    public ApplicationMap()
    {
        this.HasKey(t => t.ID);

        this.ToTable("TB_APLICATION", "aplication");

        this.Property(t => t.ID).HasColumnName("id");
        this.Property(t => t.Name).HasColumnName("name");
        this.Property(t => t.StartScriptID).HasColumnName("startscript_id");

        this.HasOptional(t => t.StartScript)
            .WithMany()
            .HasForeignKey(t => t.StartScriptID);
    }
}

public class ScriptMap : EntityTypeConfiguration<Script>
{
    public ScriptMap()
    {
        this.HasKey(t => t.ID);

        this.ToTable("TB_APLICATION", "aplication");

        this.Property(t => t.ID).HasColumnName("id");
        this.Property(t => t.Name).HasColumnName("name");

        this.HasRequired(t => t.Application)
            .WithMany(w => w.Scripts)
            .HasForeignKey(t => t.ApplicationId);
    }
}

Don't forget to tell EF about the Mappings: (Call it inside OnModelCreating ) 不要忘了告诉EF有关映射的信息:(在OnModelCreating内部调用它)

public static class MappingConfig
{
     public static void ConfigureMap(DbModelBuilder modelBuilder)
     {
         modelBuilder.Configurations.Add(new ApplicationMap());
         modelBuilder.Configurations.Add(new ScriptMap());
     }
 }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM