POCO代理无法自动设置关系
更改跟踪代理的要求之一是表示关系“多”端的导航属性必须返回实现 ICollection
的类型。
更改跟踪代理还为类提供自动关系修复功能。例如,当执行 someEmployee.Addresses.Add(address);
时,代理会自动将 address.EmployeeID
设置为值 100
并分配someEmployee
实例到导航属性 address.Employee
:
public class Employee
{
public virtual int EmployeeID { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
}
Employee someEmployee = ...;
Address address = ...;
Console.WriteLine(someEmployee.EmployeeID); // 100
Console.WriteLine(address.EmployeeID); // 20
someEmployee.Addresses.Add(address);
Console.WriteLine(address.EmployeeID); // 100
Console.WriteLine(address.Employee.EmployeeID); // 100
但是如果我们更改 Employee 类的定义,则由于某种原因代理无法自动修复关系:
public class Employee
{
private List<Address> _addresses = new List<Address>();
public virtual int EmployeeID { get; set; }
public virtual ICollection<Address> Addresses
{
get { return _addresses; }
set { _addresses = value.ToList(); }
}
}
Console.WriteLine(someEmployee.EmployeeID); // 100
Console.WriteLine(address.EmployeeID); // 20
someEmployee.Addresses.Add(address);
Console.WriteLine(address.EmployeeID); // 20
Console.WriteLine(address.Employee.EmployeeID); // 20
导航属性Employee.Addresses
确实返回一个实现 ICollection
的类型( List
),那么为什么代理不能修复关系?
谢谢
编辑
这是因为代理本身没有修复关系。它会用自己的实例化集合替换您的实例化集合,但是一旦您调用 value.ToList(),您就会用修复逻辑丢弃它的实现。
但是如果调用 value.ToList()
是原因自动关系修复不起作用,然后删除 setter
方法应该启用自动关系修复,但事实并非如此:
public class Employee
{
private List<Address> _addresses = new List<Address>();
public virtual int EmployeeID { get; set; }
public virtual ICollection<Address> Addresses
{
get { return _addresses; }
}
}
One of the requieremets for change tracking proxies is that a navigation property that represents the "many" end of a relationship must return a type that implements ICollection
.
Change tracking proxies also provide classes with automatic relationship fix-up. For example, when someEmployee.Addresses.Add(address);
is executed, proxy automatically sets address.EmployeeID
to value of 100
and also assigns someEmployee
instance to a navigation property address.Employee
:
public class Employee
{
public virtual int EmployeeID { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
}
Employee someEmployee = ...;
Address address = ...;
Console.WriteLine(someEmployee.EmployeeID); // 100
Console.WriteLine(address.EmployeeID); // 20
someEmployee.Addresses.Add(address);
Console.WriteLine(address.EmployeeID); // 100
Console.WriteLine(address.Employee.EmployeeID); // 100
But if we change the definition of Employee class, then for some reason proxy isn't able to automatically fix-up the relationship:
public class Employee
{
private List<Address> _addresses = new List<Address>();
public virtual int EmployeeID { get; set; }
public virtual ICollection<Address> Addresses
{
get { return _addresses; }
set { _addresses = value.ToList(); }
}
}
Console.WriteLine(someEmployee.EmployeeID); // 100
Console.WriteLine(address.EmployeeID); // 20
someEmployee.Addresses.Add(address);
Console.WriteLine(address.EmployeeID); // 20
Console.WriteLine(address.Employee.EmployeeID); // 20
Navigation property Employee.Addresses
does return a type that implements ICollection
( List<T>
), so why isn't proxy able to fix-up the relationship?
Thank you
EDIT
It is because the proxy itself doesn't fixup the relation. It replaces your instantiated collections with its own but once you call value.ToList() you are throwing away its implementation with fixup logic.
But if calling value.ToList()
is the reason why automatic relationship fix-up doesn't work, then removing the setter
method should enable automatic relationship fix-up, but it doesn't:
public class Employee
{
private List<Address> _addresses = new List<Address>();
public virtual int EmployeeID { get; set; }
public virtual ICollection<Address> Addresses
{
get { return _addresses; }
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是因为代理本身并没有修复关系。它用自己的实例化集合替换了您的实例化集合,但是一旦您调用 value.ToList() ,您就会用修复逻辑抛弃它的实现。使用它,它应该按预期工作:
It is because the proxy itself doesn't fixup the relation. It replaces your instantiated collections with its own but once you call
value.ToList()
you are throwing away its implementation with fixup logic. Use this instead and it should work as expected:您也可以尝试这样做:
优点是,当您使用
new
创建实体时,POCO 类中的 Addresses 集合也会自动实例化(而不是使用 CreateObject 或 创建方法)用于不需要代理的情况(例如序列化)。另一个变化是ICollection被实现为HashSet<>。而不是 List<>,确保唯一性。
You can also try this:
The advantage is that the Addresses collection in the POCO class will also be automatically instantiated when you create your entity with
new
(rather than using the CreateObject or Create methods) for use in situations where proxies are undesirable (e.g. serialization).Another change is that the ICollection is implemented as a HashSet<> instead of a List<>, ensuring uniqueness.