Entity Framework-вставка записей в дочернюю таблицу, когда родительская запись уже существует

Добрый день-

Я разрабатываю приложение Silverlight с использованием LINQ to Entity Framework для уровня доступа к данным. Моя N-уровневая модель базы данных включает около 30 таблиц с несколькими многоуровневыми отношениями родитель-потомок. Недавно начал писать мои службы данных и модульные тесты и обнаружил проблему с вставкой новой записи в дочернюю таблицу, когда запись родительской таблицы уже определена. Вот сокращенная версия моего родительские и дочерние таблицы:

РОДИТЕЛЬСКАЯ ТАБЛИЦА:

пользователи
    UserID (PK)
    Электронная почта
    Пароль
    так далее...

ДОЧЕРНЯЯ ТАБЛИЦА:

пользовательских профилей
    UserProfileID (PK)
    Различные данные профиля...
    UserID (FK -- таблица пользователей)

Итак, на данный момент у меня есть Entity Framework, который уже использовался для создания мои различные классы для ORM, и я ищу, чтобы создать службы данных для операций CRUD на моих сущностях. Ниже приведен пример кода для моего метода для вставки нового пользователей (который не имеет ссылок на родительскую таблицу):

    public User CreateUser(User newUser)
    {
        using (var _context = new ProjectDatabase())
        {
            newUser.CreatedDate = DateTime.Now;
            newUser.ModifiedDate = DateTime.Now;
            _context.AddToUsers(newUser);
            _context.SaveChanges();
        }

        return newUser;
    }

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

    public UserProfile CreateProfile(UserProfile newUserProfile)
    {
        using (var _context = new ProjectDatabase())
        {
            newUserProfile.CreatedDate = DateTime.Now;
            newUserProfile.ModifiedDate = DateTime.Now;
            _context.AddToUserProfiles(newUserProfile);
            _context.SaveChanges();
        }

        return newUserProfile;
    }

этот код, как и другой, компилируется без проблем. Однако мой модульный тест постоянно терпит неудачу. Вот код для моего модульного теста:

    [TestMethod]
    public void UserProfileCrudTest()
    {
        IProfileDataService _dataService = new ProfileDataService();

        // Pre-seeded data on a State for foreign key
        State _myState;
        using (var _context = new ProjectDatabase())
        {
            _myState = _context.States.First();
        }

        // Creating temporary User for association with new UserProfile
        User _myUser = new User()
                  {
                      Email = "test",
                      Password = "test",
                      IsActive = true,
                      NameFirst = "test",
                      NameLast = "test"
                  };

        _myUser = _dataService.CreateUser(_myUser);
        Assert.IsNotNull(_myUser);

        // Attempt to create new UserProfile, assigning foreign key
        _myUserProfile = new UserProfile()
                 { 
                     Address = "123 Main", 
                     City = "Anywhere", 
                     State = _myState, 
                     PostalCode = "63021", 
                     UserID = _myUser.UserID 
                 };

        // This call to CreateProfile throws an exception and the test fails!!
        _myUserProfile = _dataService.CreateProfile(_myUserProfile);
        Assert.IsNotNull(_myUserProfile);

        // Remaining test code... never gets this far... 
    }

Итак, на данный момент мой модульный тест выдает следующее исключение:

метод тестирования MyProject.Служб dataservices.Тесты.SecurityTests.UserProfileCrudTest выбросил исключение:

1 ответов


вам не нужно делать все эти вещи. С EF 4.0 ваш код может быть таким простым:

public UserProfile Create(UserProfile userProfile) {
    using (var context = new ProjectDatabase()) {                     
        //add the new graph to the context:
        context.UserProfiles.AddObject(userProfile);
        context.SaveChanges();
    }
    return userProfile;
}

public void UserProfileCrudTest() {    
    User _myUser = new User() {
        Email = "test",
        ...
    };
    UserProfile _myUserProfile = new UserProfile() {
        Address = "123 Main",
        ...
    };

    // join the new UserProfile to the User
    _myUserProfile.User = _myUser;
    UserProfile userProfile = Create(_myUserProfile);    
}

объяснение:

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

userProfile.User = yourUserObject
// OR
yourUserObject.UserProfiles.add(userProfile)

а затем вызовите SavingChanges ().

Если у вас есть только UserID, вы можете установить его так же, как UserProfile.UserID = идентификатор пользователя. Кстати, я знаю, что это то, что вы изначально пытались сделать, и у вас есть исключение, поэтому вот что вам нужно сделать:

1. Обновите модель из базы данных, чтобы убедиться, что она полностью синхронизирована с БД.

2. Шаг через код и убедитесь, что вы устанавливаете законный UserID для объекта UserProfile (что - то, что действительно существует в пользовательской таблице) - вы даже можете попытаться жестко его закодировать.

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