Entity Framework 6 with immutable class

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 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 the unit and value.)

It's great. We love immutability. But the Entity Framework does not recognize that I need to put X, Y and Z in the database because they do not have setters. And they should not, because it is an immutable class. There should not even be a private set .

I have this code building my model:

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

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

+5
source share
3 answers

As far as I know, EF will store both _x and X in a table so that you can publish them to private setters.

They are still immutable, with the exception of the primary key that EF must set.

Alternatively, you can add another layer: the immutable class and the model class of the EF table, and when you pull out the database form, you get an immutable object, while the mutable one will be hidden outside the DAL.

0
source

In a similar situation, I had to create a private constructor without parameters, which could use EntityFramework and made Id as a private set . This worked fine for me, and this is the best thing I could do while I was having a class, immutable.

So, in your case, the above class can be updated and simplified as follows:

 public class Point { public Distance X { get; private set; } public Distance Y { get; private set; } public Distance Z { get; private set; } public int DatabaseId { get; private set; } // DatabaseId can't be set publicly private Point() { } // Private Parameterless Constructor for EntityFramework public Point(Distance x, Distance y, Distance z) { X = x; Y = y; Z = z; } } 

Hope this helps!

0
source

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 in 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 => mX).UsePropertyAccessMode(PropertyAccessMode.Field); builder.Entity<Point>().Property(m => mY).UsePropertyAccessMode(PropertyAccessMode.Field); builder.Entity<Point>().Property(m => mZ).UsePropertyAccessMode(PropertyAccessMode.Field); } } 

The final problem is using this controller:

 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 the 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); } 
0
source

All Articles