LINQ к SQL: присоединить или не присоединить

Таким образом, я, действительно нелегко выяснять, когда я должен присоединять к объекту и когда я не должен присоединять к объекту. Первая первая вещь, вот маленькая схема моего (очень упрощена) объектная модель.

Schema

В моем DAL я создаю новый DataContext каждый раз, когда я делаю связанную с данными операцию. Скажите, например, я хочу сохранить нового пользователя. В моем бизнес-слое я создаю нового пользователя.

var user = new User();
user.FirstName = "Bob";
user.LastName = "Smith";
user.Username = "bob.smith";
user.Password = StringUtilities.EncodePassword("MyPassword123");
user.Organization = someOrganization; // Assume that someOrganization was loaded and it's data context has been garbage collected.

Теперь я хочу пойти, сохраняют этого пользователя.

var userRepository = new RepositoryFactory.GetRepository<UserRepository>();
userRepository.Save(user);

Neato! Вот моя логика сохранения:

public void Save(User user)
{
 if (!DataContext.Users.Contains(user))
 {
  user.Id = Guid.NewGuid();
  user.CreatedDate = DateTime.Now;
  user.Disabled = false;

  //DataContext.Organizations.Attach(user.Organization);
  DataContext.Users.InsertOnSubmit(user);
 }
 else 
 {
  DataContext.Users.Attach(user);
 }

 DataContext.SubmitChanges();

 // Finished here as well.
 user.Detach();
}

Так, мы здесь Вы заметите, что я комментирую бит где DataContext attachs к организации. Если я присоединяю к организации, я получаю следующее исключение:

NotSupportedException: была предпринята попытка, чтобы Присоединить или Добавить объект, который не является новым, возможно, будучи загруженным из другого DataContext. Это не поддерживается.

Хм, это не работает. Позвольте мне попробовать его, не присоединяя (т.е. прокомментировать ту строку о присоединении к организации).

DuplicateKeyException: не Может добавить объект с ключом, который уже используется.

WHAAAAT? Я могу только предположить, что это пытается ввести новую организацию, которая является, очевидно, ложью.

Так, кто такие парни соглашения?Что мне делать? Каков надлежащий подход? Кажется, что L2S делает это вполне немного тяжелее, чем это должно быть...

Править: Я просто заметил это, если я пытаюсь посмотреть на незаконченный массив изменений (dataContext. GetChangeSet ()) я получаю тот же NotSupportedException, который я описал ранее!! Что, черт возьми, L2S?!

9
задан Brad Heller 21 April 2010 в 01:33
поделиться

2 ответа

Таким образом, "прикрепление" используется, когда вы берете существующий объект из базы данных, отсоединяете его (например, маршалируя его через веб-службу в другом месте) и хотите чтобы вернуть его в базу данных. Вместо вызова .Attach () вызовите .InsertOnSubmit (). Концептуально вы почти у цели, вы просто используете неправильный метод, чтобы делать то, что хотите.

1
ответ дан 4 December 2019 в 22:27
поделиться

Возможно, под капотом это работает не совсем так, но вот как я себе это представляю: Когда вы вызываете объект из DataContext, одна из вещей, которую делает Linq, - это отслеживание изменений этого объекта во времени, чтобы он знал, что сохранить обратно, если вы вносите изменения. Если вы потеряете этот исходный контекст данных, объект Linq, вызванный из него, не будет иметь истории изменений, произошедших в нем с того момента, когда он был вызван из БД.

Например:

DbDataContext db = new DbDataContext();
User u = db.Users.Single( u => u.Id == HARD_CODED_GUID );
u.FirstName = "Foo";
db.SubmitChanges();

В этом случае, поскольку объект User был вызван из контекста данных, он отслеживал все изменения в "u" и знает, как отправить эти изменения в БД.

В вашем примере у вас был объект User, который был где-то сохранен (или передан из другого места и не имеет своего оригинального DataContext, из которого он был вызван). В этом случае вы должны присоединить его к новому контексту данных.

User u; // User object passed in from somewhere else
DbDataContext db = new DbDataContext();
u.FirstName = "Foo";
DbDataContext.Users.Attach( u );
db.SubmitChanges();

Поскольку связь между пользователем и организацией - это просто GUID (OrganizationId) в вашей модели данных, вам нужно присоединить только объект пользователя.

Я не уверен в вашем коде строительных лесов, но, возможно, что-то вроде этого:

    private const Guid DEFAULT_ORG = new Guid("3cbb9255-1083-4fc4-8449-27975cb478a5");
    public void Save(User user)
    {
        if (!DataContext.Users.Contains(user))
        {
            user.Id = Guid.NewGuid();
            user.CreatedDate = DateTime.Now;
            user.Disabled = false;
            user.OrganizationId = DEFAULT_ORG; // make the foreign key connection just
                                               // via a GUID, not by assigning an
                                               // Organization object

            DataContext.Users.InsertOnSubmit(user);
        }
        else
        {
            DataContext.Users.Attach(user);
        }

        DataContext.SubmitChanges();

    }
7
ответ дан 4 December 2019 в 22:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: