[英]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.