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