EntityFramework:模型1:0..1与流畅的api +约定的关系

时间:2016-11-15 17:32:38

标签: entity-framework

我有一个从edmx模型生成的以下类:

public partial class A
{
    public int Id { get; set; }
    public virtual B B { get; set; }
}
public partial class B
{
    public int Id { get; set; }
    public virtual A A { get; set; }
}

现有数据库不使用EF默认值,它希望A.Id成为表B的主键:

CREATE TABLE [dbo].[B] (
    [Id]    INT IDENTITY (1, 1) NOT NULL,
    PRIMARY KEY CLUSTERED ([Id] ASC)
);
CREATE TABLE [dbo].[A] (
    [Id]  INT IDENTITY (1, 1) NOT NULL,
    [BId] INT NULL,
    CONSTRAINT [fk] FOREIGN KEY ([BId]) REFERENCES [dbo].[B] ([Id])
);

使用edmx模型,我可以显式配置每一端的多重性,但我还没有找到如何使用fluent-api获得等效模型。当我执行类似以下操作并生成新数据库时,外键将放在表A而不是表B中。

modelBuilder.Entity<A>().HasOptional(a => a.B).WithRequired(b => b.A);

我猜我需要使用约定,但到目前为止我一直无法获得所需的输出。

更新

我到目前为止找到的最接近的解决方案是使用以下方法在db中生成正确的SQL:

modelBuilder.Entity<A>()
    .HasOptional(a => a.B)
    .WithOptionalDependent(b => b.A)
    .Map(c => c.MapKey("BId"));

但是,它在概念上被建模为0..1:0..1关系,我还没有找到如何设置删除A时删除B的CASCADE删除规则。

1 个答案:

答案 0 :(得分:0)

我无法找到直接解决方案,但使用以下代码似乎符合我保留现有架构和创建具有相同多重性和概念模型的要求。删除行为作为我原来的edmx模型。

我仍然对在后处理IStoreModelConvention期间不需要更新概念模型的任何解决方案感兴趣。

    {
        var overridesConvention = new OverrideAssociationsConvention();
        modelBuilder.Conventions.Add(overridesConvention);
        modelBuilder.Conventions.Add(new OverrideMultiplictyConvention(overridesConvention));
    }

    private class OverrideAssociationsConvention : IConceptualModelConvention<AssociationType>
    {
      ...
        public List<AssociationEndMember> MultiplicityOverrides { get; } = new List<AssociationEndMember>();
        public void Apply(AssociationType item, DbModel model)
        {
            if (multiplicityOverrides.Contains(item.Name))
            {
                // Defer actually updating the multiplicity until the store model is generated
                // so that foreign keys are placed in the desired tables.
                MultiplicityOverrides.Add(item.AssociationEndMembers.Last());
            }

            if (cascadeOverrides.Contains(item.Name))
            {
                item.AssociationEndMembers.Last().DeleteBehavior = OperationAction.Cascade;
            }
        }
    }

    private class OverrideMultiplictyConvention : IStoreModelConvention<EdmModel>
    {
        private readonly OverrideAssociationsConvention overrides;
        public OverrideMultiplictyConvention(OverrideAssociationsConvention overrides)
        {
            this.overrides = overrides;
        }

        public void Apply(EdmModel item, DbModel model)
        {
            overrides.MultiplicityOverrides.ForEach(o => o.RelationshipMultiplicity = RelationshipMultiplicity.One);
        }
    }