Как предотвратить повторяющиеся записи, используя шаблон UnitOfWork с кодом первой Entity Framework? - PullRequest
2 голосов
/ 19 января 2012

Я использую шаблон «Единица работы» и «Общий репозиторий». Вот оператор, который проверяет наличие дублирующейся записи:

int id = int.Parse(beer.id); //id comes from the item we're hoping to insert

if (_unitOfWork.BeerRepository.GetByID(id) == null)
     \\create a new model br
     _unitOfWork.BeerRepository.Insert(br);
     _unitOfWork.save();

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

Нарушение ограничения PRIMARY KEY 'PK_ Beers _3214EC2703317E3D'. Невозможно вставить повторяющийся ключ в объект "dbo.Beers". \ R \ nУсловие было прекращено.

Я также получаю это сообщение:

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

Класс UnitOfWork имеет мой BeerRecommenderContext, который реализует DbContext, а UnitOfWork имеет общий репозиторий для каждой сущности:

namespace BeerRecommender.Models
{
public class GenericRepository<TEntity> where TEntity : class
{
    internal BeerRecommenderContext context;
    internal DbSet<TEntity> dbSet;

    public GenericRepository(BeerRecommenderContext context)
    {
        this.context = context;
        this.dbSet = context.Set<TEntity>();
    }

    public virtual IEnumerable<TEntity> Get(
        Expression<Func<TEntity, bool>> filter = null,
        Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
        string includeProperties = "")
    {
        IQueryable<TEntity> query = dbSet;

        if (filter != null)
        {
            query = query.Where(filter);
        }

        foreach (var includeProperty in includeProperties.Split
            (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
        {
            query = query.Include(includeProperty);
        }

        if (orderBy != null)
        {
            return orderBy(query).ToList();
        }
        else
        {
            return query.ToList();
        }
    }

    public virtual TEntity GetByID(object id)
    {
        return dbSet.Find(id);
    }

    public virtual void Insert(TEntity entity)
    {
        dbSet.Add(entity);
    }

    public virtual void Delete(object id)
    {
        TEntity entityToDelete = dbSet.Find(id);
        Delete(entityToDelete);
    }

    public virtual void Delete(TEntity entityToDelete)
    {
        if (context.Entry(entityToDelete).State == EntityState.Detached)
        {
            dbSet.Attach(entityToDelete);
        }
        dbSet.Remove(entityToDelete);
    }

    public virtual void Update(TEntity entityToUpdate)
    {
        dbSet.Attach(entityToUpdate);
        context.Entry(entityToUpdate).State = EntityState.Modified;
    }

    }
}

1 Ответ

0 голосов
/ 19 января 2012

У меня есть аналогичное использование хранилища с использованием кода в первую очередь.Иногда я вижу конфликты, подобные описанному вами.Моя проблема была с отслеживанием изменений в нескольких процессах.Вставляете ли вы элементы в базу данных внутри одного процесса (используя единый контекст сущности)?

Если вы это делаете, вам следует рассмотреть параметры слияния, доступные в Entity Framework.Если вы используете опцию слияния по умолчанию (AppendOnly), то вы можете запрашивать контекст в памяти, а не обращаться к базе данных.Это может вызвать поведение, которое вы описываете.

К сожалению, насколько я понимаю, все параметры слияния еще не представлены в Code-First.Вы можете выбрать значение по умолчанию (AppendOnly) или NoTracking, которое будет каждый раз попадать в базу данных.

Надеюсь, это поможет, Davin

...