【问题标题】:Entity Framework and self-referencing collections实体框架和自引用集合
【发布时间】:2021-08-22 01:36:03
【问题描述】:

我正在尝试为位置对象建模。位置可以运送到许多其他位置并从许多位置接收。位置也可以有一个父位置。如何通过实体框架在我的数据库中表示它? 这是我到目前为止所拥有的: 位置类:

public class Location
{
    public int Id { get; set; }

    public string Name { get; set; }
    
    public string ShortName { get; set; }

    public Location ParentLocation { get; set; }

    public int? ParentLocationId { get; set; }

    public ICollection<Location> ShipToLocations { get; set; }
    public ICollection<Location> ReceiveFromLocations { get; set; }
    
}

我的 DbContext 类中的 OnModelCreating 函数:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
   modelBuilder.Entity<Location>(entity =>
   {
       entity.HasKey(x => x.Id);
       entity.HasOne(x => x.ParentLocation);
       entity.HasMany(x => x.ShipToLocations);
       entity.HasMany(x => x.ReceiveFromLocations);
    });
}

我似乎正在通过数据库获取 ParentLocationId 字段,这对我来说很有意义。 但是,ef 也会为数据库生成 LocationId 和 LocationId1 字段,这是没有意义的。按照我的理解,Entity Framework 应该生成某种形式的连接表,因为每个位置都有许多运送到位置的位置和许多从位置接收的位置,所有这些位置都是其他位置。

【问题讨论】:

标签: c# sql .net entity-framework


【解决方案1】:

由于您尝试使用单个表进行此操作,因此 EF 尝试为目标和源位置创建额外的外键。您实际上无法通过一张桌子实现这一目标。您应该有一个额外的表格,表示该位置可用的目的地。

你应该尝试像这样构建你的类:

public class Location
{
    public int Id { get; set; }

    // other fields here
    
    public int? ParentId { get; set; }
    public Location Parent { get; set; }

    public ICollection<Location> ChildLocations { get; } 
    
    public ICollection<LocationDestintaion> Destinations { get; set; }
    
    public ICollection<LocationDestintaion> Sources { get; set; }
}

public class LocationDestintaion
{
    public int SourceId { get; set; }
    public Location Source { get; set; }
    
    public int DestinationId { get; set; }
    public Location Destination { get; set; }
}

那么你会有这种ModelBuilder 配置:

modelBuilder.Entity<Location>()
            .HasOne(x => x.Parent).WithMany(x => x.ChildLocations)
            .HasForeignKey(x => x.ParentId).IsRequired(false);

modelBuilder.Entity<Location>()
            .HasMany(x => x.Destinations).WithOne(x => x.Source)
            .HasForeignKey(x => x.SourceId);
        
modelBuilder.Entity<Location>()
            .HasMany(x => x.Sources).WithOne(x => x.Destination)
            .HasForeignKey(x => x.DestinationId);

modelBuilder.Entity<LocationDestintaion>().ToTable("Paths")
            .HasKey(x => new {x.SourceId, x.DestinationId});

然后您可以像这样查询目的地和来源:

const int locationId = 1;

var availableDestinations = context.Locations.Where(x => x.Id == locationId)
            .SelectMany(x => x.Destinations).ToList();

var sourceLocations = context.Locations.Where(x => x.Id == locationId)
            .SelectMany(x => x.Sources).ToList();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-25
    • 1970-01-01
    • 2018-12-06
    相关资源
    最近更新 更多