繁体   English   中英

如何使用 Entity Framework Core 从数据库表中确定通用实体的下一个主键?

[英]How to determine the next primary key from a database table for a generic entity using Entity Framework Core?

我创建了以下通用存储库,它是我所有其他存储库的父级。

using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using FlasherData.Repositories.Interfaces;

namespace FlasherData.Repositories
{
    public abstract class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
    {
        protected readonly DbContext _context;

        public GenericRepository(DbContext context)
        {
            _context = context;
        }

        /// <summary>
        /// Finds an entity of TEntity type with the given primary key value.
        /// </summary>
        /// <param name="id"></param>
        /// <returns>The entity found or null.</returns>
        public virtual TEntity Get(int id)
        {
            try
            {
                return _context.Set<TEntity>().Find(id);
            }
            catch (Exception e)
            {
                throw new Exception($"Could not find entity: {e.Message}");
            }
        }
        /// <summary>
        /// Finds an entity of TEntity type with the given primary key value.
        /// </summary>
        /// <param name="id"></param>
        /// <returns>The entity found or null.</returns>
        public virtual async Task<TEntity> GetAsync(int id)
        {
            try
            {                
                return await _context.Set<TEntity>().FindAsync(id);
            }
            catch (Exception e)
            {
                throw new Exception($"Could not find entity: {e.Message}");
            }
        }

        /// <summary>
        /// Finds all entities of TEnitity type.
        /// </summary>
        /// <returns>A List<TEntity> of the entities found of TEntity type</returns>  
        public virtual IList<TEntity> GetAll()
        {
            try
            {
                return _context.Set<TEntity>().ToList();
            }
            catch (Exception e)
            {
                throw new Exception($"Could not find entities: {e.Message}");
            }
        }
        /// <summary>
        /// Asynchronously finds all entities of TEnitity type.
        /// </summary>
        /// <returns>A List<TEntity> of the entities found of TEntity type</returns>  
        public virtual async Task<IList<TEntity>> GetAllAsync()
        {
            try
            {                
                return await _context.Set<TEntity>().ToListAsync();
            }
            catch (Exception e)
            {
                throw new Exception($"Could not find entities: {e.Message}");
            }
        }

        /// <summary>
        /// Filters a sequence of values of TEntity type based on a predicate.
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns>An IQueryable<TEntity> that contains elements of TEntity type from the input sequence that satisfy the condition specified by the predicate.</returns>   
        public virtual IEnumerable<TEntity> Where(Expression<Func<TEntity, bool>> predicate)
        {
            try
            {
                if (predicate == null)
                {
                    throw new ArgumentNullException($"{nameof(TEntity)} predicate must not be null");
                }
                return _context.Set<TEntity>().Where(predicate);
            }
            catch (Exception e)
            {
                throw new Exception($"Could not find entity: { e.Message}");
            }
        }

        /// <summary>
        /// Filters a value of TEntity type based on a predicate.
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns>An entity of TEntity type from the input sequence that satisfy the condition specified by the predicate.</returns>   
        public virtual TEntity WhereSingleOrDefault(Expression<Func<TEntity, bool>> predicate)
        {
            if (predicate == null)
            {
                throw new ArgumentNullException($"{nameof(TEntity)} entity must not be null");
            }
            try
            {
                return _context.Set<TEntity>().SingleOrDefault(predicate);
            }
            catch (Exception e)
            {
                throw new Exception($"could not be find entity: {e.Message}");
            }
        }
        /// <summary>
        /// Asynchronously filters a value of TEntity type based on a predicate.
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns>An entity of TEntity type from the input sequence that satisfy the condition specified by the predicate.</returns>   
        public virtual async Task<TEntity> WhereSingleOrDefaultAsync(Expression<Func<TEntity, bool>> predicate)
        {
            if (predicate == null)
            {
                throw new ArgumentNullException($"{nameof(TEntity)} entity must not be null");
            }
            try
            {
                return await _context.Set<TEntity>().SingleOrDefaultAsync(predicate);
            }
            catch (Exception e)
            {
                throw new Exception($"could not be find entity: {e.Message}");
            }
        }

        /// <summary>
        /// Determines if entity with the given primary key value exists.
        /// </summary>
        /// <param name="id"></param>
        /// <returns>A boolean; true if the entity exists or false if the entity does not exist. </returns>
        public virtual bool Exists(int id)
        {
            try
            {
                var response = _context.Set<TEntity>().Find(id);
                if (response != null)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception e)
            {
                throw new Exception($"Could not find entity: {e.Message}");
            }
        }
        /// <summary>
        /// Asynchronously determines if entity with the given primary key value exists.
        /// </summary>
        /// <param name="id"></param>
        /// <returns>A boolean; true if the entity exists or false if the entity does not exist. </returns>
        public virtual async Task<bool> ExistsAsync(int id)
        {
            try
            {
                var response = await _context.Set<TEntity>().FindAsync(id);
                if (response != null)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception e)
            {
                throw new Exception($"Could not find entity: {e.Message}");
            }
        }

        /// <summary>
        /// Adds an entity to the dbcontext.
        /// </summary>
        /// <param name="entity"></param>
        /// <returns>An integer that is the primary key of the added entity.</returns>
        public virtual int Add(TEntity entity)
        {
            try
            {
                if (entity == null)
                {
                    throw new ArgumentNullException($"{nameof(TEntity)} entity must not be null");
                }
                var result = _context.Set<TEntity>().Add(entity);
                int pk = GetPrimaryKey(entity);
                return pk;
            }
            catch (Exception e)
            {
                throw new Exception($"{nameof(TEntity)} could not be added: {e.Message}");
            }
        }

        /// <summary>
        /// Asynchronously adds an entity to the dbcontext.
        /// </summary>
        /// <param name="entity"></param>
        /// <returns>An integer that is the primary key of the added entity.</returns>
        public virtual async Task<int> AddAsync(TEntity entity)
        {
            try
            {
                if (entity == null)
                {
                    throw new ArgumentNullException($"{nameof(TEntity)} entity must not be null");
                }                                
                var result = await _context.Set<TEntity>().AddAsync(entity);
                int pk = GetPrimaryKey(entity);
                return pk;
            }
            catch (Exception e)
            {
                throw new Exception($"{nameof(TEntity)} could not be added: {e.Message}");
            }
        }

        /// <summary>
        /// Adds multiple entities to the dbcontext.
        /// </summary>
        /// <param name="entity"></param>
        /// <returns>A List<int> that are the primary keys of the added entities.</int></returns>
        public virtual IList<int> AddRange(IEnumerable<TEntity> entities)
        {
            try
            {
                List<int> pks = new List<int>();

                if (entities == null)
                {
                    throw new ArgumentNullException($"{nameof(TEntity)} entity must not be null");
                }
                _context.Set<TEntity>().AddRange(entities);
                foreach (TEntity e in entities)
                {
                    pks.Add(GetPrimaryKey(e));
                }
                return pks;
            }
            catch (Exception e)
            {
                throw new Exception($"{nameof(IEnumerable<TEntity>)} could not be added: {e.Message}");
            }
        }
        /// <summary>
        /// Asynchronously adds multiple entities to the dbcontext.
        /// </summary>
        /// <param name="entity"></param>
        /// <returns>A List<int> that are the primary keys of the added entities.</int></returns>
        public virtual async Task<IList<int>> AddRangeAsync(IEnumerable<TEntity> entities)
        {            
            try
            {
                List<int> pks = new List<int>();

                if (entities == null)
                {
                    throw new ArgumentNullException($"{nameof(TEntity)} entity must not be null");
                }
                await _context.Set<TEntity>().AddRangeAsync(entities);
                foreach (TEntity e in entities)
                {
                    pks.Add(GetPrimaryKey(e));
                }
                return pks;
            }
            catch (Exception e)
            {
                throw new Exception($"{nameof(IEnumerable<TEntity>)} could not be added: {e.Message}");
            }
        }

        /// <summary>
        /// Updates the existing given entity.
        /// </summary>
        /// <param name="entity"></param>
        /// <returns>An integer that is the primary key for the updated entity.</returns>
        public virtual int Update(TEntity entity)
        {
            if (entity == null)
            {
                throw new ArgumentNullException($"{nameof(TEntity)} entity must not be null");
            }

            try
            {
                _context.Update(entity);
                _context.SaveChanges();
                return GetPrimaryKey(entity);
            }
            catch (Exception e)
            {
                throw new Exception($"{nameof(TEntity)} could not be updated: {e.Message}");
            }
        }

        /// <summary>
        /// Deletes the given entity.
        /// </summary>
        /// <param name="entity"></param>
        public virtual void Remove(TEntity entity)
        {
            try
            {
                if (entity == null)
                {
                    throw new ArgumentNullException($"{nameof(TEntity)} entity must not be null");
                }
                _context.Set<TEntity>().Remove(entity);
                _context.SaveChanges();
            }
            catch (Exception e)
            {
                throw new Exception($"{nameof(TEntity)} could not be removed: {e.Message}");
            }
        }

        /// <summary>
        /// Deletes multilple given entities.
        /// </summary>
        /// <param name="entities"></param>
        public virtual void RemoveRange(IEnumerable<TEntity> entities)
        {
            try
            {
                if (entities == null)
                {
                    throw new ArgumentNullException($"{nameof(TEntity)} entity must not be null");
                }
                _context.Set<TEntity>().RemoveRange(entities);
                _context.SaveChanges();
            }
            catch (Exception e)
            {
                throw new Exception($"{nameof(IEnumerable<TEntity>)} could not be added: {e.Message}");
            }
        }

        /// <summary>
        /// Saves changes to dbcontext for an entity
        /// </summary>
        /// <param name="entity"></param>
        /// <returns>An integer representing the number of entites changed during the save</returns>
        public virtual int SaveChanges(TEntity entity)
        {
            if (entity == null)
            {
                throw new ArgumentNullException($"{nameof(TEntity)} entity must not be null");
            }

            try
            {
                _context.Update(entity);
                return _context.SaveChanges(); 
            }
            catch (Exception e)
            {
                throw new Exception($"{nameof(TEntity)} could not be updated: {e.Message}");
            }
        }
        /// <summary>
        /// Asynchronously saves changes to dbcontext for an entity
        /// </summary>
        /// <param name="entity"></param>
        /// <returns>An integer representing the number of entites changed during the save</returns>
        public virtual async Task<int> SaveChangesAsync(TEntity entity)
        {
            if (entity == null)
            {
                throw new ArgumentNullException($"{nameof(TEntity)} entity must not be null");
            }

            try
            {
                _context.Update(entity);                
                int entitiesChanged = await _context.SaveChangesAsync();
                return entitiesChanged;
            }
            catch (Exception e)
            {
                throw new Exception($"{nameof(TEntity)} could not be updated: {e.Message}");
            }
        }

        /// <summary>
        /// Finds the primary key of the given entity
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity"></param>
        /// <returns>An integer that is the primary key for the given entity.</returns>
        public virtual int GetPrimaryKey(TEntity entity)
        {
            var keyName = _context.Model.FindEntityType(typeof(TEntity)).FindPrimaryKey().Properties
                .Select(x => x.Name).Single();

            return (int)entity.GetType().GetProperty(keyName).GetValue(entity, null);
        }

    }
}

我需要添加一个通用的 function ,我可以在其中使用实体框架从数据库中提取下一个主键。

这是我到目前为止所拥有的,但我无法从 Key object 中获取主键值。

public virtual int NextPrimaryKey()
{            
      int nextPrimaryKey = 0;
      var maxKey = _context.Model.FindEntityType(typeof(TEntity)).GetKeys().Max();
      //nextPrimarykey = ;
      return nextPrimaryKey;
}

我的部分问题可能是我是 generics 的新手,所以我不知道要寻找什么或如何询问它。

有更好的方法吗? 如果这是一个好方法,如何从 Key object 中提取主键值?

通常,获取主键不是一个好主意,因为它是不可预测的操作。 在返回“下一个”增量值时,它可能已经在使用中,因为与此同时您的数据库已更新。 如果您想事先知道一个键,您可能应该使用 GUID(或者将其添加为额外的列,或者将其用作主键)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM