我正在尝试映射一个班级,在那里我有一个相关项目的列表和一个选定的相关项目。基本上,我有一个包含任务集合的工作流,并且在任何给定时间,这些任务之一都被选择为当前任务。
public class Flow
{
public int FlowId { get; set; }
public int CurrentFlowTaskId { get; set; }
public bool IsActive { get; set; }
public virtual FlowTask CurrentFlowTask { get; set; }
public virtual ICollection<FlowTask> FlowTasks { get; set; }
}
public class FlowTask
{
public int FlowTaskId { get; set; }
public int FlowId { get; set; }
public string Discription { get; set; }
public virtual Flow Flow { get; set; }
}
我的映射如下:
public class FlowMap : EntityTypeConfiguration<Flow>
{
public FlowMap()
{
HasKey(x => x.FlowId);
Property(x => x.IsActive).IsRequired();
HasOptional(x => x.CurrentFlowTask)
.WithOptionalPrincipal()
.WillCascadeOnDelete(false);
HasMany(x => x.FlowTasks)
.WithRequired(x => x.Flow)
.HasForeignKey(x => x.FlowId)
.WillCascadeOnDelete(false);
}
}
public class FlowTaskMap : EntityTypeConfiguration<FlowTask>
{
public FlowTaskMap()
{
HasKey(x => x.FlowTaskId);
Property(x => x.Discription).HasMaxLength(25).IsRequired();
}
}
这将创建如下所示的迁移:
CreateTable(
"dbo.Flows",
c => new
{
FlowId = c.Int(nullable: false, identity: true),
CurrentFlowTaskId = c.Int(nullable: false),
IsActive = c.Boolean(nullable: false),
})
.PrimaryKey(t => t.FlowId);
CreateTable(
"dbo.FlowTasks",
c => new
{
FlowTaskId = c.Int(nullable: false, identity: true),
FlowId = c.Int(nullable: false),
Discription = c.String(nullable: false, maxLength: 25),
Flow_FlowId = c.Int(),
})
.PrimaryKey(t => t.FlowTaskId)
.ForeignKey("dbo.Flows", t => t.Flow_FlowId)
.ForeignKey("dbo.Flows", t => t.FlowId)
.Index(t => t.FlowId)
.Index(t => t.Flow_FlowId);
这里似乎不对的第一件事是在流程任务中创建的Flow_FlowId
列。
当我在LinqPad中运行以下代码块时,看不到预期的结果;创建了Flow
和FlowTask
,但是Flow.CurrentTaskId
为空,并且关闭的Flow_FlowId
列设置为与Flow.FlowId
var fi = new CompWalk.Data.FlowTask
{
Discription = "Task 1",
};
var f = new CompWalk.Data.Flow {
IsActive = true,
CurrentFlowTask = fi,
FlowTasks = new[] {
fi
}
};
Flows.Add(f);
SaveChanges();
此代码改编自几乎相同的问题here,但已有数年历史,因此可能不再适用。
在不进行多次插入和保存的情况下我能尝试的是什么?
另外,是什么原因导致生成Flow_FlowId
列?
答案 0 :(得分:1)
Flow
和FlowTask
之间有两种不同的关系类型。您通过向FlowId
添加FlowTask
来配置了一对多关系,并对其进行了配置,以便我们在迁移中使用此行
.ForeignKey("dbo.Flows", t => t.FlowId)
这是正确的。并且存在一对一的关系,其中您将Flow
标记为主体,因此FlowTask
是依赖的。实体框架将主体ID作为外键添加到从属实体以创建这种关系。在实体框架中,无法为与实体属性的一对一关系配置外键(就像您为一对多关系那样配置)。并且由于该框架,框架会为您生成外键并将其添加到从属实体(FlowTask
)。
.ForeignKey("dbo.Flows", t => t.Flow_FlowId)
您的public int CurrentFlowTaskId { get; set; }
属性只是一个常规列,而不是外键,因此在您的示例中实际上并未设置。并且Flow_FlowId
被设置为Flow.FlowId
,因为它是外键。
如果要将一对一关系外键添加到Flow
,只需更改此行
HasOptional(x => x.CurrentFlowTask)
.WithOptionalPrincipal()
.WillCascadeOnDelete(false);
到
HasOptional(x => x.CurrentFlowTask)
.WithOptionalDependent()
.WillCascadeOnDelete(false);
如果要指定密钥名称,请将其更改为以下名称
HasOptional(x => x.CurrentFlowTask)
.WithOptionalDependent()
.Map(m => m.MapKey("KeyName"))
.WillCascadeOnDelete(false);
但是,如果您决定向KeyName
实体添加Flow
属性,则迁移将产生异常:
KeyName: Name: Each property name in a type must be unique. Property name 'KeyName' is already defined.
因此您将无法直接在代码中访问此值,并且我不知道如何解决此问题。尚未研究。但是我认为应该可以将这种关系配置为一对多,并以某种方式将其使用为一对一,但是我不确定。