Удаление дочерней сущности в отношениях «многие к одному» с использованием POCO в EF4 CTP5 - PullRequest
3 голосов
/ 31 декабря 2010

Короткая версия:

Используя классический пример Order и OrderLine, как я могу сделать следующее в POCO:

public partial class Order {

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

В отношении многие-к-одному, использующему POCO, это только удаляет ссылку на Заказ в OrderLine. Есть ли способ удалить сущность OrderLine автоматически? Или я должен внедрить хранилище или поднять код в службу? Использовать триггер в базе данных? Есть ли образец или лучшая практика для этого? Все примеры, которые я нахожу в Интернете, похоже, используют несколько простых дополнений и «Вот почему вы должны использовать POCO»: -)

Положение:

Используя EF4 CTP5 в VS2010, генерируя POCO, которые остаются невежественными (динамические прокси), я борюсь с тем, как обрабатывать удаление связанных «дочерних» сущностей.

Вопрос: Метод Remove в ICollection Relative ниже в классе Employee удаляет только связь, но не конечную сущность. Есть ли способ заставить его также удалить сущность, не вводя хранилище / службу или не извлекая код из сущности? Я хочу чистый класс POCO.

Мотивация: Относительная сущность не может существовать без сотрудника, поэтому наиболее естественным местом для обработки добавления, удаления и т. Д. Является класс 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();

и относительный элемент добавляется в таблицу «Относительный» и ссылается на сотрудника.

Однако, если я хочу реализовать метод DeleteRelative в классе Employee:

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.

Что вполне понятно, поскольку поле EmployeeId в Relative не может быть пустым.

Итак, опять же, возможно ли решить эту проблему каким-либо иным способом, кроме внедрения репозиториев / контекста в сущность (что, по-моему, противоречит цели POCO).

Другая альтернатива - это обернуть все это в сценарий службы или транзакции, но опять же, я бы хотел, чтобы EF4 справился с этим, не настраивая / не подключая сущности и не делая сценарии транзакции.

Любая помощь очень ценится, и если вам нужна дополнительная информация, скажите мне.

О, и счастливого нового года всем вам. : -)

1 Ответ

1 голос
/ 20 марта 2011

Если это вариант в архитектуре вашего приложения, вы можете рассмотреть возможность включения динамических прокси на своих объектах.Это позволяет контексту создавать подкласс вашей сущности, который переопределяет ваши свойства для отслеживания изменений.В вашем случае это удалит строки, соответствующие вашему объекту, когда объект потеряет свои ссылки (при условии, что вы вызываете SaveChanges () в контексте).

Динамические прокси могут быть включены, когда

  • Класс является публичным и не закрытым.
  • У класса есть открытые или защищенные свойства (в вашем примере это свойство коллекции, содержащее «строки заказа»).
  • Класс имеет открытый или защищенный конструктор без параметров.

Глядя на вопрос, который, по-видимому, соответствует этим требованиям.

Включение динамических прокси-серверов можно выполнить, установив свойство в своем контексте (это также можно сделать в представлении конструктора Entity Framework.):

this.ContextOptions.ProxyCreationEnabled = true;
...