在DDD中,通常保护实体的属性如下:
public class Customer
{
private Customer() { }
public Customer(int id, string name) { /* ...populate properties... */ }
public int Id { get; private set; }
public string Name { get; private set; }
// and so on...
}EF使用反射,这样它就可以处理所有这些私事。
但是,如果您需要在不加载实体的情况下附加一个实体(这是一件非常常见的事情):
var customer = new Customer { Id = getIdFromSomewhere() }; // can't do this!
myContext.Set<Customer>().Attach(customer);这不起作用,因为Id设置器是私有的。
如何处理语言和DDD之间的这种不匹配?
想法:
Id公开(并破坏DDD)我认为最好的折衷办法是使用反射,并设置私有Id属性,就像EF一样。是的,它反射速度慢,但比从数据库加载要快得多。是的,这是欺骗,但至少就域而言,不经过构造函数就无法实例化该实体。
您如何处理这种情况?
PS --我做了一个简单的基准测试,使用反射创建100万个实例需要花费大约10s的时间。因此,与命中数据库或EF执行的反射相比,额外的开销非常小。
发布于 2017-05-19 13:56:15
这就是我在做的,用反射。我认为这是最好的选择。
var customer = CreateInstanceFromPrivateConstructor<Customer>();
SetPrivateProperty(p=>p.ID, customer, 10);
myContext.Set<Customer>().Attach(customer);
//...and all the above was just for this:
order.setCustomer(customer);
myContext.SaveChanges();这两个反射方法的实现并不重要。重要的是:
发布于 2017-05-19 08:31:10
“习惯”含蓄地意味着它不是一条硬规则,所以如果你有具体的理由在你的应用程序中违反这些规则,那就去做吧。公开属性设置比考虑这一点更好:这不仅是因为性能问题,还因为它使得在应用程序中放置不必要的副作用变得更加容易。反思不是处理这件事的方法。
但我认为这里的第一个问题是,为什么首先要从外部设置对象的ID。EF主要使用ID来标识对象,您不应该将ID用于应用程序中的其他逻辑。
假设您有强烈的理由想要更改ID,我实际上认为您是在您刚刚在评论中输入的源代码中给出了答案:
因此,您将有方法来控制对象发生了什么,并在这样做时,约束属性,使其不暴露于设置或修改“willy nilly”。
您可以保留私有setter并使用方法来设置ID。
编辑:在阅读了this之后,我尝试自己做一些更多的测试,您可以拥有以下内容:
public class Customer
{
private Customer() { }
public Customer(int id) { /* only sets id */ }
public Customer(int id, string name) { /* ...populate properties... */ }
public int Id { get; private set; }
public string Name { get; private set; }
// and so on...
public void SetName(string name)
{
//set name, perhaps check for condition first
}
}
public class MyController
{
//...
var customer = new Customer(getIdFromSomewhere());
myContext.Set<Customer>().Attach(customer);
order.setCustomer(customer);
myContext.SaveChanges(); //sets the customer to order and saves it, without actually changing customer: still read as unchanged.
//...
}这段代码使私有设置程序保持原样(当然,您需要编辑方法),然后只将所需的更改推送到db。正如上面的链接所解释的那样,只使用附加后所做的更改,并且您应该确保不手动将对象的状态设置为修改,否则所有属性都会被推送(可能清空对象)。
https://stackoverflow.com/questions/44064187
复制相似问题