Entity Framework 6 with an Immutable Class

c# entity-framework entity-framework-6 immutability

Question

I have a Point class:

// My immutable Point class
public class Point
{
    private readonly Distance _x;
    private readonly Distance _y;
    private readonly Distance _z;

    public Distance X
    {
        get { return _x; }
    }

    public Distance Y
    {
        get { return _x; }
    }

    public Distance Z
    {
        get { return _x; }
    }

    // Ok, so this isn't immutable... but it's purely for EF
    public int DatabaseId { get; set; }

    public Point(Distance x, Distance y, Distance z)
    {
        _x = x;
        _y = y;
        _z = z;
    }
}

(Distance is a custom class that stores a unit and a value.)

That's great. We love immutability. But Entity Framework won't recognize that I need to put X, Y, and Z in the database because they don't have setters. And they shouldn't, because this is an immutable class. There shouldn't even be a private set.

I have this code building my model:

    modelBuilder.Entity<Point>()
        .HasKey(point => point.DatabaseId);

Is there any way to preserve the true immutability of this class but also make it so that EF6 can access and store these values?

1
5
3/27/2018 2:49:24 PM

Popular Answer

EF Core 2.0.1:

Model:

public class Point
{
    [Obsolete("For ORM(EF) use only", true)]
    public Point() { }

    public Point(Distance x, Distance y, Distance z)
    {
        _x = x;
        _y = y;
        _z = z;
    }

    public int Id { get; set; }

    public Distance X { get => _x; }
    private Distance _x;

    public Distance Y { get => _y; }
    private Distance _y;

    public Distance Z { get => _z; }
    private Distance _z;
}

Let EF fill the private fields

public class DomainDbContext : DbContext
{      
    /*skipping other stuff you have here*/ 

    public DbSet<Point> Points { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        // Fill Properties with private fields 
        builder.Entity<Point>().Property(m => m.X).UsePropertyAccessMode(PropertyAccessMode.Field);
        builder.Entity<Point>().Property(m => m.Y).UsePropertyAccessMode(PropertyAccessMode.Field);
        builder.Entity<Point>().Property(m => m.Z).UsePropertyAccessMode(PropertyAccessMode.Field);
    }
}

Final issue is using this with a controller so:

public class PointViewModel // has default parameterless constructcor
{       
    public int Id { get; set; }

    public Distance X { get; set; }

    public Distance Y { get; set; }

    public Distance Z { get; set; }
}

Use in controller:

[HttpPost]
public async Task<IActionResult> Create([Bind("X,Y,Z")] PointViewModel info)
{
     if (ModelState.IsValid)
     {
         var point = new Point(info.X, info.Y, info.Z);

         _context.Add(point);
         await _context.SaveChangesAsync();
         return RedirectToAction(nameof(Index));
      }
      return View(info);
}
1
3/27/2018 2:43:54 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow