EF Code First Общая проверка Наличие объекта без общего идентификатора Свойство? - PullRequest
4 голосов
/ 24 января 2012

РЕДАКТИРОВАТЬ: ОТВЕТИТЬ ВНИЗ ЭТОГО ВОПРОСА

Хорошо, у меня есть несколько общих функций EF (большинство из которых я получил здесь), но они, похоже, не работают.

У меня есть 3 класса:

 public class Group : Entity
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public virtual GroupType GroupType { get; set; }

    public virtual ICollection<User> Users { get; set; }
}
 public class GroupType: Entity
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
}

 public class User: Entity
{
    public Guid Id { get; set; }
    public string FirstName { get; set; }
    public string MiddleName { get; set; }
    public string LastName { get; set; }
    public string UserName { get; set; }

    public virtual ICollection<Group> Groups { get; set; }
 }

Мои операции CRUD:

public void Insert(TClass entity)
    {
        if (_context.Entry(entity).State == EntityState.Detached)
        {
            _context.Set<TClass>().Attach(entity);
        }
        _context.Set<TClass>().Add(entity);
        _context.SaveChanges();
    }

public void Update(TClass entity)
    {
        DbEntityEntry<TClass> oldEntry = _context.Entry(entity);

        if (oldEntry.State == EntityState.Detached)
        {
            _context.Set<TClass>().Attach(oldEntry.Entity);
        }

        oldEntry.CurrentValues.SetValues(entity);
        //oldEntry.State = EntityState.Modified;

        _context.SaveChanges();
    }

public bool Exists(TClass entity)
    {
        bool exists = false;

        if(entity != null)
        {
            DbEntityEntry<TClass> entry = _repository.GetDbEntry(entity);
            exists = entry != null;
        }

        return exists;
    }

public void Save(TClass entity)
    {
        if (entity != null)
        {
            if (Exists(entity))
                _repository.Update(entity);
            else
                _repository.Insert(entity);
        }
    }

Наконец, я вызываю этот код в следующем методе:

public string TestCRUD()
    {

        UserService userService = UserServiceFactory.GetService();
        User user = new User("Test", "Test", "Test", "TestUser") { Groups = new Collection<Group>() };

        userService.Save(user);
        User testUser = userService.GetOne(x => x.UserName == "TestUser");

        GroupTypeService groupTypeService = GroupTypeServiceFactory.GetService();
        GroupType groupType = new GroupType("TestGroupType2", null);

        groupTypeService.Save(groupType);

        GroupService groupService = GroupServiceFactory.GetService();
        Group group = new Group("TestGroup2", null) { GroupType = groupType };
        groupService.Save(group);

        user.Groups.Add(group);
        userService.Save(user);

        return output;
    }

Когда я доберусь до:

 user.Groups.Add(group);
 userService.Save(user);

Я получаю следующую ошибку:

Произошла ошибка при сохранении сущностей, которые не предоставляют свойства внешнего ключа для своих отношений. Свойство EntityEntries вернет значение NULL, поскольку один объект не может быть определен как источник исключения. Обработка исключений при сохранении может быть упрощена путем предоставления свойств внешнего ключа в типах объектов. Подробности смотрите в InnerException.

Со следующим внутренним исключением:

Оператор INSERT вступил в конфликт с ограничением FOREIGN KEY "User_Groups_Source". Конфликт произошел в базе данных «DBNAME», таблице «dbo.Users», столбце «Id».

Проблемы:

1) Exists всегда возвращает true, даже если сущность была только что создана в памяти и, следовательно, вставка никогда не вызывается только Update внутри метода Save, я думаю, это потому, что я не понимаю DbEntityEntry полностью, потому что и сам и Entry.Entity никогда не равны нулю. Как я могу проверить существование?

2) Даже если весь код выполняется в TestCRUD до самого конца, ни одна из этих сущностей фактически не сохраняется в базе данных. Я уверен, что моя база данных настроена правильно, потому что мой пользовательский инициализатор всегда удаляет и воссоздает базу данных и каждый раз вставляет начальные данные. Вероятно, это потому, что обновление всегда вызывается, как указано в номере 1.

Есть идеи как починить?

РЕДАКТИРОВАТЬ: ОТВЕТ

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

public bool Exists(TClass entity)
    {
        bool exists = false;

        PropertyInfo info  = entity.GetType().GetProperty(GetKeyName());
        if (_context.Set<TClass>().Find(info.GetValue(entity, null)) != null)
            exists = true;

        return exists;
    }

Все остальные методы начали работать как положено. Однако в той же строке я получил другую ошибку:

user.Groups.Add(group);
userService.Save(user);

что было:

Нарушение ограничения PRIMARY KEY 'PK_ GroupTypes _00551192'. Невозможно вставить дубликат ключа в объект «dbo.GroupTypes». Заявление было прекращено.

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

1 Ответ

1 голос
/ 24 января 2012

Как я могу проверить существование?

Я обычно видел, как люди проверяют, существует ли сущность, проверяя, больше ли ее свойство Id, чем ноль.,Вы должны иметь возможность либо использовать интерфейс со свойством Id, либо (если вы предполагаете иметь объекты с несколькими свойствами ключа), вы можете сделать так, чтобы каждая сущность переопределяла абстрактный базовый класс, переопределяя свойство Exists для проверки егособственные свойства идентификатора для значений не по умолчанию.Или вы можете использовать отражение, чтобы найти свойство или свойства идентификатора автоматически, , как описано здесь .

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

...