繁体   English   中英

关系的条件映射

[英]Conditional Mapping on Relationships

使用实体框架(代码优先),我试图映射以下两个实体之间的条件/过滤关系:

建造
BuildingId
建筑名称

区域
areaID表示
的ParentId
AREANAME
IsSubArea

建筑可以有很多区域
区域可以有许多(子) 区域

我想创建建筑区域之间的关系,其中标有'IsSubArea'的区域被过滤掉。 在此上下文中,ParentId将与Building相关 ,否则,ParentId将是另一个Area 这将允许我创建具有许多区域的建筑物,并且每个区域可以具有许多子区域,从而创建树形结构。

最接近我发现的解决方案与'软删除'功能( )有关:

modelBuilder.Entity<Foo>().Map(m => m.Requires("IsDeleted").HasValue(false));

转换为适合我的例子:

modelBuilder.Entity<Area>().Map(m => m.Requires("IsSubArea").HasValue(false));

但据我所知,这与建筑物的关系无关。

另一种解决方案是在Building上创建一个属性,该属性指定用于返回相关区域的查询定义( ):

public class Building
{
    public int BuildingId {get; set;}
    public string BuildingName {get; set;}

    public IQueryable<Area> BuildingAreas
    {
        get 
        {
            return from area in areas
                   where area.IsSubArea == false
                   and   area.ParentId == BuildingId
                   select area;

            //Assume I have a reference to relevant DbSets
        }
    }
}

这个解决方案可以工作,但不像条件映射那样优雅。

另一种解决方案是从Area继承并创建2个子类:

BuildingArea
areaID表示
BuildingId
AREANAME

分区
areaID表示
ParentAreaId
AREANAME

每个都继承自Area并根据需要设置'IsSubArea'字段。 这个解决方案感觉更整洁,但我不知道如何在Entity Framework中实现它。

有没有办法在关系上指定条件映射?
有没有更好的方法来实现这种结构?

更新1 :找到这个这个继承的指南,似乎符合我的要求。 但是,这些教程都没有定义派生类型之间的关系。 我将在今晚用关于每层结构表(TPH)方法尝试的内容更新问题。

更新2
我将尝试描述我尝试基于上面的教程链接实现的每层次表(TPH)方法。 请原谅我,如果这有点复杂(也许我在想它)。

楷模
建筑类与OP保持一致。

我创建了一个抽象基类,定义了每个派生类型(BuildingArea和SubArea)共有的Area属性:

public abstract class Area
{
    protected Area(bool isSubArea)
    {
        IsSubArea = isSubArea;
        SubAreas = new List<SubArea>();
    }

    public int AreaId { get; set; }
    public int ParentId { get; set; }
    public string AreaName { get; set; }
    public bool IsSubArea { get; private set; } //note the private set

    public virtual ICollection<SubArea> SubAreas { get; set; }
}

然后我有2个派生类型继承自Area

public class BuildingArea : Area
{
    public BuildingArea () : base(false)
    {}

    public virtual Building ParentBuilding { get; set; }        
}

public class SubArea : Area
{
    public SubArea(): base(true)
    {}

    // This is of type `Area` because parent could be either `BuildingArea` or `SubArea`
    public virtual Area Parent { get; set; }        
}

然后我有以下2个EntityTypeConfigurations:

public class BuildingAreaMap : EntityTypeConfiguration<BuildingArea>
{
    public BuildingAreaMap ()
    {
        // Primary Key
        HasKey(t => t.AreaId);

        // Properties
        Property(t => t.AreaName)
            .IsRequired()
            .HasMaxLength(256);

        // Table & Column Mappings 
        ToTable("Areas");
        Property(t => t.AreaId).HasColumnName("AreaId");
        Property(t => t.ParentId).HasColumnName("ParentId");
        Property(t => t.AreaName).HasColumnName("AreaName");
        Property(t => t.IsSubArea).HasColumnName("IsSubArea");

        // This is the discriminator column
        Map(m => m.Requires("IsSubArea").HasValue(false));

        HasRequired(a => a.Site).WithMany(s => s.SiteAreas).HasForeignKey(k => k.ParentId);
    }


public class SubAreaMap : EntityTypeConfiguration<SubArea>
{
    public SubAreaMap()
    {
        // Primary Key
        HasKey(t => t.AreaId);

        // Properties
        Property(t => t.AreaName)
            .IsRequired()
            .HasMaxLength(256);

        // Table & Column Mappings 
        ToTable("AssetHealthAreas");
        Property(t => t.AreaId).HasColumnName("AreaId");
        Property(t => t.ParentId).HasColumnName("ParentId");
        Property(t => t.AreaName).HasColumnName("AreaName");
        Property(t => t.IsSubArea).HasColumnName("IsSubArea");

        // This is the discriminator column
        Map(m => m.Requires("IsSubArea").HasValue(true));

        HasRequired(a => a.Parent).WithMany(s => s.SubAreas).HasForeignKey(k => k.ParentId);
    }
}

此代码构建成功,但我收到以下运行时错误:

Map was called more than once for type 'SiteArea' and at least one of the calls didn't specify the target table name.

但我正在指定目标表名称(每个EntityTypeConfiguration类中一次)。 所以我删除了SubArea的EntityTypeConfiguration但是我得到了同样的错误。

其中一个教程将映射拉出EntityTypeConfiguration类,并将其放入OnModelCreating处理程序中,如下所示:

modelBuilder.Entity<Area>()
    .Map<BuildingArea>(m => m.Requires("IsSubArea").HasValue(false))
    .Map<SubArea>(m => m.Requires("IsSubArea").HasValue(true));

这也给了我同样的错误。

如果我从等式中删除关系,我会得到关于ParentId属性的不同错误:

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

更新3

我试图创建的模型的图像......

ERD

更新4

我将尝试简化我的模型以匹配以下内容。 如果下面的解决方案有效,我将需要更多的业务逻辑来导航树,但它应该是可管理的。

ERD2

对于创建TPH类时的错误:我认为这是因为您不应该将鉴别器列作为类中的属性。

从基类中删除属性IsSubArea。

创建新实例时,EF应自动检测类型并相应地填充IsSubArea。

暂无
暂无

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

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