本文介绍了实体框架流利API不考虑基类的属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

EF 6.1:

我们刚刚起步,有很多PF继承的项目。选定继承DB映射类型是每个层级表。问题是,尝试使用外接迁移产生迁移时,下面的错误被抛出:

We just started a project that has a lot pf inheritance. The selected inheritance db mapping type is the table per hierarchy. The problem is that when trying to generate the migration using the add-migration, the following error is thrown :

The foreign key component 'VersionId' is not a declared property on type 'SER'. Verify that it has not been explicitly excluded from the model and that it is a valid primitive property.

下面是类&放大器;配置类使用的:

Here are the classes & the configuration classes used :

public class Version : BaseObject
{
    public virtual ICollection<SER> ListOfSER { get; set; }
}

public abstract class AbsractR : BaseObject
{
    public int ParentId { get; set; }
    public int ChildId { get; set; }

    public int VersionId { get; set; }
    public virtual Version Version { get; set; }
}

public class SER : AbstractR
{
    public int SEDId
    {
        get
        {
            return base.ChildId;
        }
        set
        {
            base.ChildId = value;
        }
    }
    public virtual SED SED { get; set; }
}

public abstract class AbstractD : BaseObject
{
}

public class SED : AbstractD
{
    public virtual ICollection<SER> ListOfSER { get; set; }
}


public class SDContext : BaseContext
{
    public DbSet<Version> Versions { get; set; }
    public DbSet<AbstractD> Ds { get; set; }
    public DbSet<AbstractR> Rs { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Configurations.Add(new VersionConfiguration());

        #region Refs
        modelBuilder.Configurations.Add(new AbstractRConfiguration());
        modelBuilder.Configurations.Add(new SERConfiguration());
        #endregion

        #region Defs
        modelBuilder.Configurations.Add(new AbstractDConfiguration());
        modelBuilder.Configurations.Add(new SEDConfiguration());
        #endregion
    }
}

public class BaseObjectConfiguration<T> : EntityTypeConfiguration<T> where T : BaseObject
{
    public BaseObjectConfiguration()
    {
        #region Key
        this.HasKey(bo => bo.Id);
        #endregion

        #region Properties
        this.Property(bo => bo.Id).IsRequired();
        this.Property(bo => bo.IsDeleted).IsRequired();
        this.Property(bo => bo.LastModificationDate).IsOptional();
        this.Property(bo => bo.OptimisticVersion).IsConcurrencyToken().IsRequired().IsRowVersion();
        this.Property(bo => bo.CreationDate).IsRequired();
        this.Property(bo => bo.DeletionDate).IsOptional();
        #endregion
    }
}

public class VersionConfiguration : BaseObjectConfiguration<Version>
{
    public VersionConfiguration() : base()
    {
        #region Properties
        #endregion

        #region Objects
        this.HasMany(mdv => mdv.ListOfSER).WithRequired().HasForeignKey(ser => ser.VersionId).WillCascadeOnDelete(false);
        #endregion

        #region Table
        this.ToTable("Versions");
        #endregion
    }
}

public class AbstractRConfiguration : BaseObjectConfiguration<AbstractR>
{
    public AbstractRConfiguration()
        : base()
    {
        #region Properties
        this.Property(ser => ser.VersionId).IsRequired();
        #endregion

        #region Objects
        this.HasRequired(ar => ar.Version).WithMany().HasForeignKey(ar => ar.VersionId).WillCascadeOnDelete(false);
        #endregion

        #region Table
        this.ToTable("Refs");
        #endregion
    }
}

public class SERConfiguration : BaseObjectConfiguration<SER>
{
    public SERConfiguration()
        : base()
    {
        #region Properties
        this.Ignore(ser => ser.SEDId);
        #endregion

        #region Objects
        this.HasRequired(ser => ser.SED).WithMany(sed => sed.ListOfSER).HasForeignKey(ser => ser.ChildId).WillCascadeOnDelete(false);
        #endregion

        #region Table
        this.ToTable("Refs");
        #endregion
    }
}

public class AbstractDConfiguration : BaseObjectConfiguration<AbstractD>
{
    public AbstractDConfiguration() : base()
    {
        this.ToTable("Defs");
    }
}

public class SEDConfiguration : BaseObjectConfiguration<SED>
{
    public SEDConfiguration()
        : base()
    {
        #region Properties
        #endregion

        #region Objects
        this.HasMany(sed => sed.ListOfSER).WithRequired(sed => sed.SED).HasForeignKey(sed => sed.ChildId).WillCascadeOnDelete(false);
        #endregion

        #region Table
        this.ToTable("Defs");
        #endregion
    }
}



我知道我们可以用在[ForeignKey的]属性来告诉一个派生类的导航属性应使用父抽象类定义的列。我们想避免使用DataAnnotations。我只是不明白为什么它抛出这个错误。 版本导航属性在AbstractR配置,而不​​是在SER配置(这应该也是工作,因为SER从AbstractR继承)定义的,对吗?

I know we can use the [ForeignKey] attribute to tell that the navigation property on a derived class should use the column defined in the parent abstract class. We would like to avoid using DataAnnotations. I just don't get why it throw this error. The "Version" navigation property is defined in the AbstractR configuration and not in the SER configuration (which should also work since SER inherits from AbstractR), am I right ?

其次,删除版本属性和放大器时;映射,同样的问题会出现与childID的与的ParentId在SER映射中使用属性。这是一个知道的问题? ?难道我做错了什么。

Secondly, when removing the Version property & mapping, the same problem appears with the "ChildId" and "ParentId" property used in the SER mapping. Is this a know problem ? Am I doing something wrong ?

PS:本的ParentId映射已为简便起见被删除,因为它似乎是同样的问题,因为childID的映射

PS : The ParentId mapping has been removed for simplicity since it seems to be the same problem as the ChildId mapping.

有没有人任何想法,为什么这种问题是怎么回事?

Has anyone any idea why this kind of problem is happening ?

更新

一些调查研究后,似乎流利的API不能映射使用基类的属性。是对的吗 ?这是一个通缉的行为吗?为什么在DataAnnotations能够使用基类的属性和不流利的API?并非所有插入的每一个类中的基类的属性或者是具有某种装饰图案读?

After some more research, it appeared that Fluent API cannot use base class properties for the mapping. Is that right ? Is this a wanted behavior ? Why are the DataAnnotations able to use base class properties and not Fluent API ? Aren't all the base class properties inserted inside every classes or is it read with some kind of decorator pattern ?

推荐答案

可以使用基类属性,只要本金还使用类型基类的导航性能外键关联。

You can use base class properties as foreign key associations as long as the principal also uses navigation properties of type base class.

委托人(版本)已宣布 ListOfSER 类型的导航属性 SER 那样依赖

The Principal (Version) has declared ListOfSER as navigation property of type SER as Dependent

public class Version : BaseObject
{
    public virtual ICollection<SER> ListOfSER { get; set; }
}



,但配置使用基类属性( VERSIONID )的外键关联

public class VersionConfiguration : BaseObjectConfiguration<Version>
{
    public VersionConfiguration()
        : base()
    {
        HasMany(mdv => mdv.ListOfSER)
            .WithRequired()
            .HasForeignKey(ser => ser.VersionId) // -> belongs to base class
            .WillCascadeOnDelete(false);
    }
}



配置的,看看代码摘录

Which is not allowed when configuring ForeignKeyConstraintConfiguration, take a look at the code excerpt

foreach (var dependentProperty in dependentPropertyInfos)
{
    var property
        = dependentEnd.GetEntityType() // -> SER
            .GetDeclaredPrimitiveProperty(dependentProperty); // -> VersionId

    if (property == null) // VersionId is not part of SER metamodel
    {
        throw Error.ForeignKeyPropertyNotFound(
            dependentProperty.Name, dependentEnd.GetEntityType().Name);
    }

    dependentProperties.Add(property);
}



解决方案1 ​​将改变<$从 SER C $ C> ListOfSER 键入 AbstractR

The solution 1 would be changing the ListOfSER type from SER into AbstractR.

public class Version : BaseObject
{
    public virtual ICollection<AbstractR> ListOfSER { get; set; }
}

这将使更多的意义上说, VERSIONID 是在基类中定义,任何派生类型应该能够使用外键关联,对不对?但不幸的是版本类型只允许 SER 要与版本相关

This will make more sense, the VersionId is defined on base class, any derived type should be able to use this foreign key association, right? But unfortunately the Version type only allows SER to be associated with Version.

您也可以定义流利的API配置时不一致。

You also have inconsistency when defining fluent api configuration.

public class VersionConfiguration : BaseObjectConfiguration<Version>
{
    public VersionConfiguration()
        : base()
    {
        HasMany(mdv => mdv.ListOfSER)
            .WithRequired() // -> this should be WithRequired(x => x.Version)
            .HasForeignKey(ser => ser.VersionId)
            .WillCascadeOnDelete(false);
    }
}
public class AbstractRConfiguration : BaseObjectConfiguration<AbstractR>
{
    public AbstractRConfiguration()
        : base()
    {
        HasRequired(ar => ar.Version)
            .WithMany() // -> this should be WithMany(x => x.ListOfSER)
            .HasForeignKey(ar => ar.VersionId)
            .WillCascadeOnDelete(false);
    }
}



甚至,你不必对配置两侧。只要把它无论是在 VersionConfiguration AbstractRConfiguration 就足够了。

解决方案2 将移动版本 VERSIONID 从基类 SER ,如果你想版本只与 SER

The solution 2 would be moving the Version and VersionId from base class to SER, if you want Version only to be associated with SER.

public class Version : BaseObject
{
    public virtual ICollection<SER> ListOfSER { get; set; }
}
public abstract class AbstractR : BaseObject
{
}
public class SER : AbstractR
{
    public int VersionId { get; set; }
    public virtual Version Version { get; set; }
}

和配置无论是在版本配置或 SER 配置

And configuring either on Version configuration or SER configuration.

public class VersionConfiguration : BaseObjectConfiguration<Version>
{
    public VersionConfiguration()
        : base()
    {
        HasMany(mdv => mdv.ListOfSER)
            .WithRequired(x => x.Version)
            .HasForeignKey(ser => ser.VersionId)
            .WillCascadeOnDelete(false);
    }
}
public class SERConfiguration : BaseObjectConfiguration<SER>
{
    public SERConfiguration()
        : base()
    {
        HasRequired(ar => ar.Version)
            .WithMany(x => x.ListOfSER)
            .HasForeignKey(ar => ar.VersionId)
            .WillCascadeOnDelete(false);
    }
}

这篇关于实体框架流利API不考虑基类的属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-15 14:23