ASP .NET Core 在获取所有数据之前处理 UnitOfWork
ASP .NET Core disposing UnitOfWork before getting all data
我正在实施一个通用存储库 + 工作单元模式以及一个 WebApi 项目。我在获取一个实体并包含引用它的另一个实体的集合时遇到问题。
我首先通过代码映射了以下实体:
public class Ingredient : BaseEntity
{
public string Name { get; set; }
public string Amount { get; set; }
public Guid RecipeId { get; set; }
public virtual Recipe Recipe { get; set; }
}
public class Recipe : BaseEntity
{
public string Name { get; set; }
public string Description { get; set; }
public string ImagePath { get; set; }
public virtual ICollection<Ingredient> Ingredients { get; set; }
}
这是我的工作单位:
public class UnitOfWork<TContext> : IRepositoryFactory, IUnitOfWork<TContext>, IUnitOfWork where TContext : DbContext
{
private readonly TContext context;
private Dictionary<Type, object> repositories;
public UnitOfWork(TContext context)
{
this.context = context ?? throw new ArgumentNullException(nameof(context));
}
public TContext Context => context;
public IRepository<TEntity> GetRepository<TEntity>() where TEntity : BaseEntity
{
if (repositories == null)
{
repositories = new Dictionary<Type, object>();
}
var type = typeof(TEntity);
if (!repositories.ContainsKey(type))
{
repositories.Add(type, new Repository<TEntity>(context));
}
return (IRepository<TEntity>)repositories[type];
}
public int Commit()
{
return context.SaveChanges();
}
public void Dispose()
{
context?.Dispose();
}
}
还有我的通用存储库:
public class Repository<T> : IRepository<T> where T : BaseEntity
{
protected readonly DbContext dbContext;
protected readonly DbSet<T> dbSet;
public Repository(DbContext context)
{
dbContext = context;
dbSet = dbContext.Set<T>();
}
public T GetEntity(Guid id)
{
return dbSet.Find(id);
}
public T GetEntity(Guid id, params Expression<Func<T, object>>[] includeProperties)
{
IEnumerable<string> properties = GetProperties(includeProperties);
IQueryable<T> queryable = dbSet;
foreach (var property in includeProperties)
{
queryable = dbSet.Include(property);
}
return queryable.FirstOrDefault(x => x.Id == id);
}
[...]
private static IEnumerable<string> GetProperties(Expression<Func<T, object>>[] includeProperties)
{
List<string> includelist = new List<string>();
foreach (var item in includeProperties)
{
MemberExpression body = item.Body as MemberExpression;
if (body == null)
throw new ArgumentException("The body must be a member expression");
includelist.Add(body.Member.Name);
}
return includelist.AsEnumerable();
}
}
控制器正在注入 RecipeService。在控制器中我有这个方法:
[HttpGet("{id}", Name = "Get")]
public IActionResult Get(Guid id)
{
var recipe = recipeService.GetRecipe(id);
if (recipe == null)
{
return NotFound();
}
return Ok(recipe);
}
食谱服务注入 IUnitOfWork 并具有以下方法:
public Recipe GetRecipe(Guid id)
{
return repository.GetEntity(id, r => r.Ingredients);
}
另外我注册的服务如下:
services.AddScoped<IRepositoryFactory, UnitOfWork<TContext>>();
services.AddScoped<IUnitOfWork, UnitOfWork<TContext>>();
services.AddScoped<IUnitOfWork<TContext>, UnitOfWork<TContext>>();
services.AddScoped<IRecipeService, RecipeService>();
我的问题是当我得到一个指定的食谱(连同它的成分)时我得到一个 "The connection has been restarted" 错误(在 firefox 中)。在调试时,我可以看到我有配方及其成分。但是当返回 Ok(recipe) 并将结果映射到实体时,IUnitOfWork 在获得第一个成分后被处理。
谁能帮帮我?谢谢
问题是我有一个循环引用我没有得到任何异常。
我通过在 Startup class 的 ConfigureServices 方法中添加以下内容来修复:
services.AddMvc().AddJsonOptions(options =>
{
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
我正在实施一个通用存储库 + 工作单元模式以及一个 WebApi 项目。我在获取一个实体并包含引用它的另一个实体的集合时遇到问题。
我首先通过代码映射了以下实体:
public class Ingredient : BaseEntity
{
public string Name { get; set; }
public string Amount { get; set; }
public Guid RecipeId { get; set; }
public virtual Recipe Recipe { get; set; }
}
public class Recipe : BaseEntity
{
public string Name { get; set; }
public string Description { get; set; }
public string ImagePath { get; set; }
public virtual ICollection<Ingredient> Ingredients { get; set; }
}
这是我的工作单位:
public class UnitOfWork<TContext> : IRepositoryFactory, IUnitOfWork<TContext>, IUnitOfWork where TContext : DbContext
{
private readonly TContext context;
private Dictionary<Type, object> repositories;
public UnitOfWork(TContext context)
{
this.context = context ?? throw new ArgumentNullException(nameof(context));
}
public TContext Context => context;
public IRepository<TEntity> GetRepository<TEntity>() where TEntity : BaseEntity
{
if (repositories == null)
{
repositories = new Dictionary<Type, object>();
}
var type = typeof(TEntity);
if (!repositories.ContainsKey(type))
{
repositories.Add(type, new Repository<TEntity>(context));
}
return (IRepository<TEntity>)repositories[type];
}
public int Commit()
{
return context.SaveChanges();
}
public void Dispose()
{
context?.Dispose();
}
}
还有我的通用存储库:
public class Repository<T> : IRepository<T> where T : BaseEntity
{
protected readonly DbContext dbContext;
protected readonly DbSet<T> dbSet;
public Repository(DbContext context)
{
dbContext = context;
dbSet = dbContext.Set<T>();
}
public T GetEntity(Guid id)
{
return dbSet.Find(id);
}
public T GetEntity(Guid id, params Expression<Func<T, object>>[] includeProperties)
{
IEnumerable<string> properties = GetProperties(includeProperties);
IQueryable<T> queryable = dbSet;
foreach (var property in includeProperties)
{
queryable = dbSet.Include(property);
}
return queryable.FirstOrDefault(x => x.Id == id);
}
[...]
private static IEnumerable<string> GetProperties(Expression<Func<T, object>>[] includeProperties)
{
List<string> includelist = new List<string>();
foreach (var item in includeProperties)
{
MemberExpression body = item.Body as MemberExpression;
if (body == null)
throw new ArgumentException("The body must be a member expression");
includelist.Add(body.Member.Name);
}
return includelist.AsEnumerable();
}
}
控制器正在注入 RecipeService。在控制器中我有这个方法:
[HttpGet("{id}", Name = "Get")]
public IActionResult Get(Guid id)
{
var recipe = recipeService.GetRecipe(id);
if (recipe == null)
{
return NotFound();
}
return Ok(recipe);
}
食谱服务注入 IUnitOfWork 并具有以下方法:
public Recipe GetRecipe(Guid id)
{
return repository.GetEntity(id, r => r.Ingredients);
}
另外我注册的服务如下:
services.AddScoped<IRepositoryFactory, UnitOfWork<TContext>>();
services.AddScoped<IUnitOfWork, UnitOfWork<TContext>>();
services.AddScoped<IUnitOfWork<TContext>, UnitOfWork<TContext>>();
services.AddScoped<IRecipeService, RecipeService>();
我的问题是当我得到一个指定的食谱(连同它的成分)时我得到一个 "The connection has been restarted" 错误(在 firefox 中)。在调试时,我可以看到我有配方及其成分。但是当返回 Ok(recipe) 并将结果映射到实体时,IUnitOfWork 在获得第一个成分后被处理。
谁能帮帮我?谢谢
问题是我有一个循环引用我没有得到任何异常。
我通过在 Startup class 的 ConfigureServices 方法中添加以下内容来修复:
services.AddMvc().AddJsonOptions(options =>
{
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});