2

Assuming I have data model defined like this:

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

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

I would like to map it into the following database tables:

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

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

My [GeometryData] BLOB basically consists of Points IDs that make up the geometry and a couple of additional meta-information.

Taking the meta stuff away, those BLOBs would look like this:

[ 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 ]

(that is (N+1)*4 bytes for each BLOB.)

BLOB is used (instead of a simple one-to-many relation) for a couple of performance reasons. That is something that can not be changed.

I created the following entities to project the model:

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; }
}

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

Any ideas how a mapping like this could be resolved?

1 Answer 1

1

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

Ok, let's define

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}
    }
        }
    };

I think you can populate the tables using the Configuration.Seed.

with the following pseudo code

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

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

or by a standard update with 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.

Besides the specific EF implementation of your context, I think that the following code could give you an idea of the Linq part.

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()
    }
    );
Sign up to request clarification or add additional context in comments.

3 Comments

what exactly do you mean by specific EF implementation? I am quite new to EF itself and would really appreciate a piece of advice
@bashis Ok, received: I'll try to expand this answer, adding the EF context
I guess you have to override the Configuration.Seed to populate the tables and I've added a pointer to your provided geometries as a starting point in my edit.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.