Уведомление:
1. Все «сущности», упомянутые в этой статье, генерируются LINQ TO SQL (т. е. .dbml).
2. Вам необходимо понимать, как LINQ TO SQL реализует ассоциации таблиц, EntitySet и EntityRef.
Возможно, увидев заголовок, вы подумаете, что вопрос относительно абстрактный, поэтому позвольте мне привести пример, чтобы подробно объяснить проблему.
В N-уровневой архитектуре, основанной на LINQ TO SQL, если нам нужно обновить объект, процесс должен быть следующим:
процесс
BLL.GetModel(p=>p.id==1) --> Измените соответствующее значение атрибута (поля) --> BLL.Update(сущность сущности) --> DAL.Update(сущность сущности) --> Обновление выполнено успешно
На данный момент нам необходимо передать этот объект с бизнес-уровня (BLL) на уровень доступа к данным (DAL). Когда метод GetModel возвращает объект, DataContext будет немедленно освобожден, а затем повторно создан, когда DAL. Выполняется метод обновления (сущности). Создайте DataContext для выполнения операции обновления; видно, что переданный объект передается из первого DataContext в другой DataContext. При работе с разными DataContext в LINQ TO SQL необходимо выполнить дополнительные операции. выполняться первым, то есть context.Entity. Attach(entity,true) Наконец context.SubmitChanges();
Давайте посмотрим на код:
код
класс БЛЛ
{
частный DAL только для чтения dal = новый DAL();
public LinqToSqlProvider.User GetModel (выражение Expression<Func<LinqToSqlProvider.User, bool>>)
{
дал.GetModel(выражение);
}
общедоступное обновление void (объект LinqToSqlProvider.User)
{
дал.Обновление(сущность);
}
}
класс ДАЛ
{
public LinqToSqlProvider.User GetModel (выражение Expression<Func<LinqToSqlProvider.User, bool>>)
{
Запись LinqToSqlProvider.User = новый CriTextBroadcast.LinqToSqlProvider.User();
используя (контекст CriTextBroadcastDBDataContext = DataContext)
{
запись = context.User.SingleOrDefault(выражение);
}
обратный вход;
}
общедоступное обновление void (объект LinqToSqlProvider.User)
{
используя (контекст CriTextBroadcastDBDataContext = DataContext)
{
context.User.Attach(запись, правда);
context.SubmitChanges();
}
}
}
Фактически, когда мы используем приведенный выше код для работы, произойдет это исключение:
Попытка присоединения или добавления объекта. Этот объект не является новым, может быть загружен из другого контекста данных...
Проверив кучу информации, но безрезультатно, я наконец увидел аналогичный вопрос в зарубежном посте. Получается, что таблица, соответствующая этой сущности, имеет несколько связанных таблиц, таких как: Пользователь -> Сообщение, Пользователь -> Изображения и т.д.
Такие атрибуты, как EntitySet<Message> Message, будут автоматически генерироваться при создании классов сущностей. Поскольку мы не считываем это связанное содержимое вместе при получении объекта, при присоединении (Attach) в этих атрибутах возникает исключение ObjectDisposeException. используемый для запроса этого объекта, был освобожден.
Решение:
код
/// <сводка>
/// Вспомогательная сущность LinqToSql отделена от исходного DataContext
/// </сводка>
/// <typeparam name="TEntity"></typeparam>
/// <param name="entity"></param>
public static void Detatch<TEntity>(объект TEntity)
{
Введите t =entity.GetType();
Свойства System.Reflection.PropertyInfo[] = t.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
foreach (свойство var в свойствах)
{
имя строки = свойство.Имя;
если (свойство.PropertyType.IsGenericType &&
property.PropertyType.GetGenericTypeDefinition() == typeof(EntitySet<>))
{
property.SetValue(entity, null, null);
}
}
Поля System.Reflection.FieldInfo[] = t.GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
foreach (поле var в полях)
{
имя строки = поле.Имя;
если (field.FieldType.IsGenericType &&
field.FieldType.GetGenericTypeDefinition() == typeof(EntityRef<>))
{
поле.SetValue(сущность, ноль);
}
}
System.Reflection.EventInfo eventPropertyChanged = t.GetEvent("PropertyChanged");
System.Reflection.EventInfo eventPropertyChanging = t.GetEvent("PropertyChanging");
если (eventPropertyChanged!= ноль)
{
eventPropertyChanged.RemoveEventHandler(entity, null);
}
если (eventPropertyChanging! = ноль)
{
eventPropertyChanging.RemoveEventHandler(entity, null);
}
}
После получения сущности вам следует использовать метод Detach(entity), чтобы отделить сущность от исходного DataContext, а затем присоединить ее к новому DataContext.