C# - Entity Framework 代码优先 - 将对象映射到两个表中

C# - Entity Framework code-first - map object into two tables

假设我有这样定义的数据模型:

class Geometry
{
   public ICollection<Point> Points { get; set; }
}

class Point
{
   public int X { get; set; }
   public int Y { get; set; }
}

我想将其映射到以下数据库表中:

GeometriesTable
-- [GeometryId] int, key
-- [GeometryData] <-- a BLOB here!!!

PointsTable
-- [PointId] int, key
-- [GeometryId] int, foreign key
-- [X] int
-- [Y] int

我的 [GeometryData] BLOB 基本上由构成几何图形的点 ID 和一些额外的元信息组成。

除去元数据,那些 BLOB 将如下所示:

[ N (points count) - 4 bytes ]
[ Points[0].Id     - 4 bytes ] 
[ Points[1].Id     - 4 bytes ] 
[ Points[2].Id     - 4 bytes ] 
... 
[ Points[N-1].Id   - 4 bytes ]

(即每个 BLOB (N+1)*4 个字节。)

出于几个性能原因,使用 BLOB(而不是简单的一对多关系)。那是无法改变的。

我创建了以下实体来投影模型:

class GeometryEntity
{
   [Key]
   [Column("GeometryId")]
   public int Id { get; set; } 

   [Column("GeometryData")]
   public byte[] Data { get; set; }
}

class PointEntity
{
   [Key]
   [Column("PointId")]
   public int Id { get; set; }

   [Column("GeometryId")]
   public int GeometryId { get; set; }

   [Column("X")]
   public int X { get; set; }

   [Column("Y")]
   public int Y { get; set; }
}

现在,如果我有一些 IEnumerable<Geometry>,我希望能够填充表格(一个 DbSet<GeometryEntity> 和一个 DbSet<PointEntity>)。特殊问题是我不知道如何将 PointsTable 中的点 ID 分配给几何 BLOB 中的相应点 ID。

知道如何解决这样的映射吗?

Now, provided I have some IEnumerable<Geometry> I would like to be able to populate the tables (a DbSet<GeometryEntity> and a DbSet<PointEntity>).

好的,让我们定义

IEnumerable<Geometry> ProvidedGeometries =
    new Geometry[]
    {
        new Geometry()
        {
            Points = new PointEntity[]
    {
        new PointEntity() { GeometryId=1, X=1, Y=1, Id = 1},
        new PointEntity() { GeometryId=1, X=1, Y=2, Id = 2},
        new PointEntity() { GeometryId=1, X=2, Y=1, Id = 3},
        new PointEntity() { GeometryId=1, X=2, Y=2, Id = 4}
    }
        },
    new Geometry()
        {
            Points = new PointEntity[]
    {
        new PointEntity() { GeometryId=2, X=1, Y=1, Id = 5},
        new PointEntity() { GeometryId=2, X=1, Y=2, Id = 6}
    }
        }
    };

我认为您可以使用 Configuration.Seed.

填充表格

用下面的伪代码

protected override void Seed(YourContext context)
{
    context.GeometryEntities.AddOrUpdate(
        // see the following Linq part
        );

    context.PointEntities.AddOrUpdate(
        // see the following Linq part
        );
}

或通过 SaveChanges

的标准更新
using (var ctx = new YourContext())
{
   ctx.PointEntities.AddRange(Points);       //see below
   ctx.GeometryEntites.AddRange(Geometries); // " "
   ctx.SaveChanges();
}

The particular problem is that I don't know how to assign points IDs from the PointsTable to the corresponding points IDs in my geometry BLOBs.

除了 contextspecific EF implementation 之外,我认为以下代码可以让您了解Linq 部分。

IEnumerable<PointEntity> Points =ProvidedGeometries
                    .SelectMany(g => g.Points);


var geometries = Points.GroupBy(
    p => p.GeometryId,
    p => BitConverter.GetBytes(p.Id),
    (id, points) =>
    new GeometryEntity()
    {
        Id = id,
        Data = 
        BitConverter.GetBytes(points.Count()).Concat(
            points.Aggregate( (a,b) => a.Concat(b).ToArray() )
        ).ToArray()
    }
    );