изменить внешний ключ для объекта linq

У меня есть репозиторий CRUD:

public class CrudRepository<T> : ICrudRepository<T>
        where T : class, IUnique
    {
        static DataContext db = new DataContext();

        protected DataContext DataContext { get { return db; } }

        public virtual IQueryable<T> GetAll()
        {
            return db.GetTable<T>();
        }

        public virtual void Add(T item)
        {
            db.GetTable<T>().InsertOnSubmit(item);
        }

        public virtual void Save()
        {
            db.SubmitChanges();
        }

        public virtual T Get(int id)
        {
            return GetAll().FirstOrDefault(t => t.Id.Equals(id));
        }
    }

Я использую статический контекст данных для всех экземпляров вне репозитория. Я хочу изменить сущность внешнего ключа, поэтому попробую следующее решение:

CrudRepository<Employee> employeeRepository = new CrudRepository<Employee >();
Employee employee = employeeRepository.Get(employeeId)
employee.OfficeId = officeId;
employeeRepository.Save();

Но это вызывает следующее исключение:

ForeignKeyReferenceAlreadyHasValueException

Итак, я пытаюсь найти второе решение:

CrudRepository<Employee> employeeRepository = new CrudRepository<Employee >();
Employee employee = employeeRepository.Get(employeeId)
employee.Office = new CrudRepository<Office>().Get(officeId);
employeeRepository.Save();

Но он генерирует исключение с следующим сообщением:

Была сделана попытка прикрепить или добавить объект, который не является новым, возможно, загруженный из другого DataContext.

что я могу сделать? в чем проблема?


person mehran    schedule 17.02.2010    source источник


Ответы (1)


На меня бросаются три вещи.

employee.OfficeId = officeId; 

Если у класса Employee есть свойство OfficeId и свойство Office, для внесения изменений необходимо использовать свойство Office. Свойство Office автоматически создается на основе отношения в конструкторе linq.

Если вместо этого вы хотите использовать манипуляции на основе идентификатора, удалите связь между сотрудником и офисом в конструкторе (обратите внимание: это не меняет базу данных, а просто меняет сопоставления, используемые генератором кода).

new CrudRepository<Employee >();  
new CrudRepository<Office>().Get(officeId); 

Каждый репозиторий Crud имеет свой собственный текст. Объекты, загруженные из разных контекстов данных, не могут смешиваться. Предположим, им разрешили смешиваться - когда вы вызываете SubmitChanges, какой DataContext отвечает за сохранение?

В конечном итоге это означает, что ваша реализация CrudRepository будет чем-то, от чего вы захотите отказаться, если хотите продолжить использование LinqToSql. Поддержка операций Crud над одним классом не так уж и полезна. По крайней мере, это только сквозные вызовы, и их будет легко заменить прямыми вызовами метода DataContext.

static DataContext db = new DataContext(); 

Это чертовски. DataContext не является потокобезопасным.

person Amy B    schedule 17.02.2010
comment
Я хочу использовать манипуляции с базами идентификаторов, чтобы уменьшить накладные расходы на загрузку объекта отношения загрузки, но не во всех ситуациях, поэтому мне нужны оба из них. Я использовал два разных класса репозитория, но с одним статическим контекстом данных, поэтому они загружаются из одного DataContext, и поэтому я ожидаю, что это сработает. и, наконец, спасибо за напоминание о том, что DataContext не является потокобезопасным. поэтому я думаю, что могу использовать сеанс для хранения экземпляра Singleton DataContext. - person mehran; 18.02.2010
comment
CrudRepository ‹Employee› и CrudRepository ‹Office› - это разные типы, и каждый имеет свой собственный статический экземпляр DataContext. - person Amy B; 18.02.2010
comment
Итак, я думаю, что могу поместить контекст статических данных в одноэлементную фабрику, такую ​​как класс, и использовать этот класс в CrudRepository. - person mehran; 27.02.2010