使用EF4 CTP5中的POCO以多对一关系删除子实体

时间:2010-12-31 00:13:00

标签: c# entity-framework-4 poco

简短版:

使用经典的Order和OrderLine示例,如何在POCO中执行以下操作:

public partial class Order {

    public void RemoveInvalidOrderLines() {
        OrderLines.Remove(OrderLines.Where(ol => ol.Quantity > MaxQuantity));
    }
}

在使用POCO的多对一关系中,这仅删除OrderLine中对Order的引用。有没有办法自动删除OrderLine实体?或者我是否必须注入存储库或将代码提升到服务中?在数据库中使用触发器?这有什么模式或最佳实践吗?我在网上找到的所有例子似乎都使用了一些简单的添加内容,“这就是你应该使用POCO的原因”: - )

情况:

在VS2010中使用EF4 CTP5,生成持久性无知的POCO(动态代理),我在如何处理相关“子”实体的删除方面遇到了困难。

问题: 下面的Employee类中的ICollection Relative中的Remove方法仅删除关系,而不删除最终实体。有没有办法强制它删除实体,而无需注入存储库/服务或从实体中提取代码?我想要一个干净的类似POCO的课程。

动机: 没有员工,相对实体不能存在,因此处理添加,删除等最自然的地方是在Employee类中。再说一遍,我愿意接受建议。 : - )

示例: 一个员工可以有很多亲戚。 Employee类有一个存储库,提供常用的查找程序。我希望Employee能够删除亲属,而不仅仅是FK关系。我是否必须注入存储库或类似物才能执行此操作?我试图将上下文和存储库保留在POCO之外。

假设以下表格:

Employee:             
Id int (PK, not null)
Name varchar

Relative:
 Id int (PK, not null)
 EmployeeId int (FK, not null)
 Name varchar

生成以下POCO:

public partial class Employee {
...
    public virtual ICollection<Relative> Relatives
    {

        get
        {
            if (_relatives == null)
            {
                var newCollection = new FixupCollection<Relative>();
                newCollection.CollectionChanged += FixupRelatives;
                _relatives = newCollection;
            }
            return _relatives;
        }
        set
        {
            if (!ReferenceEquals(_relatives, value))
            {
                var previousValue = _relatives as FixupCollection<Relative>;
                if (previousValue != null)
                {
                    previousValue.CollectionChanged -= FixupRelatives;
                }
                _relatives = value;
                var newValue = value as FixupCollection<Relative>;
                if (newValue != null)
                {
                    newValue.CollectionChanged += FixupRelatives;
                }
            }
        }
    }

当然,

Relative:
public partial class Relative {
...
 public virtual Employee Employee
    {
        get { return _employee; }
        set
        {
            if (!ReferenceEquals(_employee, value))
            {
                var previousValue = _employee;
                _employee = value;
                FixupEmployee(previousValue);
            }
        }
    }
    private Employee _employee;


}

现在,人们可以这样做:

var employeeRepository = new EmployeeRepository(dbContext);
var employee = employeeRepository.Get(1234);
var relative = new Relative { Name = "Lars" };
employee.Relatives.Add(relative); 
context.SaveChanges();

并将亲属添加到Relative表中,并引用该员工。

但是,如果我想在Employee-class中实现DeleteRelative方法:

public void DeleteRelative(string name) {
     Relatives.Remove(Relatives.FirstOrDefault());
}

(假设亲戚存在的天真代码等)

我明白了:

System.InvalidOperationException: The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.

这是完全可以理解的,因为Relative的EmployeeId字段不能为null。

因此,除了将存储库/上下文注入实体之外,还有可能以任何方式解决这个问题(恕我直言,这种方式违背了POCO的目的)。

另一种选择是将它全部包装在服务或事务脚本中,但同样,我希望EF4能够在没有配置/连接实体或执行事务脚本的情况下处理这个问题。

非常感谢任何帮助,如果您需要更多信息,请告诉我。

噢,祝大家新年快乐。 : - )

1 个答案:

答案 0 :(得分:1)

如果它是应用程序架构中的一个选项,您可以考虑在您的实体上启用动态代理。这使上下文能够创建实体的子类,从而覆盖您的属性以跟踪更改。在您的情况下,当对象丢失它的引用时,这将删除与您的对象相对应的行(假设您在上下文中调用SaveChanges())。

时可以启用动态代理
  • 课程是公开的,没有密封。
  • 该类具有公共或受保护的属性(在您的示例中特别是包含“订单行”的集合属性)。
  • 该类具有公共或受保护的无参数构造函数。

看看你似乎满足这些要求的问题。

启用动态代理可以通过在上下文中设置属性来完成(也可以在Entity Framework设计器视图中完成):

this.ContextOptions.ProxyCreationEnabled = true;