带有不可变类的实体框架6
本文关键字:实体 框架 不可变 | 更新日期: 2023-09-27 18:11:11
我有一个Point
类:
// 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
是一个自定义类,存储一个单位和一个值)
太好了。我们喜欢不变性。但实体框架无法识别我需要把X Y和Z放到数据库中因为它们没有setter。它们不应该这样,因为这是一个不可变类。甚至不应该有private set
。
我有这个代码来构建我的模型:
modelBuilder.Entity<Point>()
.HasKey(point => point.DatabaseId);
是否有办法保持这个类的真正的不变性,但也使它使EF6可以访问和存储这些值?
在类似的情况下,我必须创建一个私有无参数构造函数, EntityFramework可以使用并使Id
作为private set
。这对我来说工作得很好,这是我在保持类不可变的时间内所能做的最好的事情。
所以在你的情况下,上面的类可以更新和简化如下:
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;
}
}
希望这对你有帮助!
EF Core 2.0.1:
模型:
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;
}
让EF填充私有字段
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);
}
}
最后一个问题是将此与控制器一起使用,因此:
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; }
}
在控制器中使用:
[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);
}
据我所知EF将在表中存储_x
和X
,因此您必须使用私有设置器将它们设置为公共。
除了EF必须能够设置的主键外,它们仍然是不可变的。
或者你可以添加另一层:不可变类和EF表模型类,当你从数据库中取出时,你会得到一个不可变对象,而可变对象将隐藏在DAL之外。