扩展模型对象(例如 Product)并添加插入数据库的 Create() 方法是否正确? (MVC 5 Entity Framework 6)
Is it proper form to extend a model object (e.g. Product) and add a Create() method that inserts into the database? (MVC 5 Entity Framework 6)
所以我目前正在扩展 Entity Framework 为我的数据库中的每个表自动生成的 classes。我在这些进行扩展的部分 classes 中放置了一些有用的方法来处理数据。
但是,我的问题是关于在数据库中插入行。在我的扩展 classes 中包含一个方法来处理这个问题会是一种好的形式吗?
例如,在 Product 控制器的 Create 方法中有这样的内容:
[HttpPost]
public ActionResult Create(Product p)
{
p.InsertThisProductIntoTheDatabase(); //my custom method for inserting into db
return View();
}
我觉得这件事有些不对劲,但我也说不准。感觉这个功能应该放在通用的 MyHelpers.cs class 或其他东西中,然后就这样做:
var h = new MyHelpers();
h.InsertThisProductIntoTheDatabase(p);
大家怎么看?我更愿意以 "correct" 的方式进行。
MVC 5、EF 6
编辑:InsertThisProductIntoTheDatabase 方法可能类似于:
public partial class Product()
{
public void InsertThisProductIntoTheDatabase()
{
var context = MyEntities();
this.CreatedDate = DateTime.Now;
this.CreatedByID = SomeUserClass.ID;
//some additional transformation/preparation of the object's data would be done here too. My goal is to bring all of this out of the controller.
context.Products.Add(this);
}
}
你为什么不简单地使用:
db.Products.Add(p);
db.SaveChanges();
您的代码会更简洁,而且您将来管理它并获得帮助肯定会更容易。互联网上可用的大多数示例都使用此模式。扩展方法和实体看起来不愉快。
顺便说一句:InsertThisProductIntoTheDatabase()
方法名是不是太长了?
我看到的一个问题是 entity framework DBContext 是一个工作单元。如果在将 Application_BeginRequest 传递给控制器构造函数时在 Application_BeginRequest 上创建了一个工作单元,那么它将作为整个请求的一个工作单元。也许它只更新了您场景中的 1 个实体,但您可能正在将更多信息写入数据库。除非您将所有内容都包装在 TransactionScope 中,否则所有这些保存都将是独立的,这可能会使您的数据库处于不一致的状态。即使您用 TransactionScope 包装所有内容,我也很确定事务将被提升到 DTC,因为您在单个控制器中建立多个物理连接并且 sql 服务器不是那么智能。
走 BeginRequest 路线似乎比向所有实体添加方法以保存自身更省力。这里的另一个问题是 EF 实体应该是一个对它自己的持久性一无所知的实体。这就是 DbContext 的用途。因此,将引用放回 DbContext 会打破这种隔离。
你的第二个原因,将审计信息添加到实体,再次将其添加到每个实体需要大量工作。您可以覆盖上下文中的 SaveChanges 并为每个实体执行一次。看到这个 answer.
沿着这条路走下去,我认为您违反了 SOLID 设计原则,因为您的实体违反了 SRP。引入一堆内聚,你最终会编写比你需要的更多的代码。所以我反对按照你的方式去做。
所以我目前正在扩展 Entity Framework 为我的数据库中的每个表自动生成的 classes。我在这些进行扩展的部分 classes 中放置了一些有用的方法来处理数据。
但是,我的问题是关于在数据库中插入行。在我的扩展 classes 中包含一个方法来处理这个问题会是一种好的形式吗?
例如,在 Product 控制器的 Create 方法中有这样的内容:
[HttpPost]
public ActionResult Create(Product p)
{
p.InsertThisProductIntoTheDatabase(); //my custom method for inserting into db
return View();
}
我觉得这件事有些不对劲,但我也说不准。感觉这个功能应该放在通用的 MyHelpers.cs class 或其他东西中,然后就这样做:
var h = new MyHelpers();
h.InsertThisProductIntoTheDatabase(p);
大家怎么看?我更愿意以 "correct" 的方式进行。
MVC 5、EF 6
编辑:InsertThisProductIntoTheDatabase 方法可能类似于:
public partial class Product()
{
public void InsertThisProductIntoTheDatabase()
{
var context = MyEntities();
this.CreatedDate = DateTime.Now;
this.CreatedByID = SomeUserClass.ID;
//some additional transformation/preparation of the object's data would be done here too. My goal is to bring all of this out of the controller.
context.Products.Add(this);
}
}
你为什么不简单地使用:
db.Products.Add(p);
db.SaveChanges();
您的代码会更简洁,而且您将来管理它并获得帮助肯定会更容易。互联网上可用的大多数示例都使用此模式。扩展方法和实体看起来不愉快。
顺便说一句:InsertThisProductIntoTheDatabase()
方法名是不是太长了?
我看到的一个问题是 entity framework DBContext 是一个工作单元。如果在将 Application_BeginRequest 传递给控制器构造函数时在 Application_BeginRequest 上创建了一个工作单元,那么它将作为整个请求的一个工作单元。也许它只更新了您场景中的 1 个实体,但您可能正在将更多信息写入数据库。除非您将所有内容都包装在 TransactionScope 中,否则所有这些保存都将是独立的,这可能会使您的数据库处于不一致的状态。即使您用 TransactionScope 包装所有内容,我也很确定事务将被提升到 DTC,因为您在单个控制器中建立多个物理连接并且 sql 服务器不是那么智能。
走 BeginRequest 路线似乎比向所有实体添加方法以保存自身更省力。这里的另一个问题是 EF 实体应该是一个对它自己的持久性一无所知的实体。这就是 DbContext 的用途。因此,将引用放回 DbContext 会打破这种隔离。
你的第二个原因,将审计信息添加到实体,再次将其添加到每个实体需要大量工作。您可以覆盖上下文中的 SaveChanges 并为每个实体执行一次。看到这个 answer.
沿着这条路走下去,我认为您违反了 SOLID 设计原则,因为您的实体违反了 SRP。引入一堆内聚,你最终会编写比你需要的更多的代码。所以我反对按照你的方式去做。