【发布时间】:2021-09-20 09:14:01
【问题描述】:
我正在尝试为我的 Telegram Bot 创建一个 N 层架构。我创建了 DAL、BLL 和 PL。我想将实体 News 添加到我的数据库中。但是我的上下文有些问题。
我的数据库上下文:
public class ApplicationContext : DbContext
{
public DbSet<News> News { get; set; }
public DbSet<User> Users { get; set; }
public ApplicationContext(DbContextOptions<ApplicationContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<News>().Property(tn => tn.Id).ValueGeneratedOnAdd();
modelBuilder.Entity<User>().Property(tn => tn.Id).ValueGeneratedOnAdd();
modelBuilder.Entity<News>().Property(tn => tn.Title).IsRequired();
modelBuilder.Entity<News>().Property(tn => tn.Href).IsRequired();
modelBuilder.Entity<News>().Property(tn => tn.Image).IsRequired();
modelBuilder.Entity<News>().Property(tn => tn.Date).IsRequired();
modelBuilder.Entity<User>().Property(tn => tn.UserId).IsRequired();
modelBuilder.Entity<User>().Property(tn => tn.UserName).IsRequired();
modelBuilder.Entity<User>().Property(tn => tn.DateOfStartSubscription).IsRequired();
base.OnModelCreating(modelBuilder);
}
}
UoW 接口:
public interface IUnitOfWork : IDisposable
{
INewsRepository News { get; }
IUserRepository Users { get; }
int Complete();
}
UoW 类:
public class UnitOfWork : IUnitOfWork
{
public IUserRepository Users { get; }
public INewsRepository News { get; }
private readonly ApplicationContext _context;
public UnitOfWork(ApplicationContext context)
{
_context = context;
Users = new UserRepository.UserRepository(_context);
News = new NewsRepository.NewsRepository(_context);
}
public int Complete() => _context.SaveChanges();
public void Dispose() => _context.Dispose();
}
我的 DAL 通用存储库:
async Task IGenericRepository<T>.AddAsync(T entity) => await _context.Set<T>().AddAsync(entity);
DAL 注入:
public static class DALInjection
{
public static void Injection(IServiceCollection services)
{
services.AddTransient(typeof(IGenericRepository<>), typeof(GenericRepository<>));
services.AddTransient<IUserRepository, UserRepository.UserRepository>();
services.AddTransient<INewsRepository, NewsRepository.NewsRepository>();
services.AddTransient<IUnitOfWork, UnitOfWork.UnitOfWork>();
}
}
我的 BLL 服务类:
public class ParserService : IParser
{
private IUnitOfWork _unitOfWork;
private readonly IMapper _mapper;
public ParserService(IUnitOfWork unitOfWork, IMapper mapper)
{
_unitOfWork = unitOfWork;
_mapper = mapper;
}
private async Task SaveArticles(IEnumerable<NewsDTO> articlesDTO)
{
var articles = _mapper.Map<IEnumerable<NewsDTO>, IEnumerable<News>>(articlesDTO);
await _unitOfWork.News.AddAsync(articles.First());
_unitOfWork.Complete();
}
BLL 注入:
public static class BLLInjection
{
public static void Injection(IServiceCollection services)
{
DALInjection.Injection(services);
services.AddTransient<IParser, ParserService>();
services.AddTransient<IArticleService, ArticleService>();
services.AddAutoMapper(typeof(CommonMappingProfile));
}
}
我的 PL:
private static async Task SendArticleAsync(long chatId, int offset, int count)
{
var articles = await _parser.MakeHtmlRequest(offset, count);
foreach (var article in articles)
{
var linkButton = KeyboardGoOver("Перейти", article.Href);
await _client.SendPhotoAsync(chatId: chatId, photo: article.Image,
caption: $"*{article.Title}*", parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown, replyMarkup: linkButton);
}
await OnLoadMoreNewsAsync(chatId, offset + count, count);
}
PL 启动类:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddDbContext<ApplicationContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection"),
b => b.MigrationsAssembly(typeof(ApplicationContext).Assembly.FullName)));
BLLInjection.Injection(services);
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "TelegramBot.WebApi", Version = "v1" });
});
}
当我尝试调试时,我遇到了这个错误,但我无法解决这个问题。
_context = Database = {"无法访问已释放的上下文实例。此错误的常见原因是释放从依赖注入中解析的上下文实例,然后尝试在应用程序的其他地方使用相同的上下文实例。这可能哦...
有人可以帮我解决这个问题吗?
【问题讨论】:
-
错误出现在您未发布的代码中。不要一开始就使用“通用存储库”反模式。 DbContext 已经是一个工作单元,一个 DbSet 已经是一个存储库。像 EF Core 这样的 ORM 已经抽象了持久性机制。
AddAsync没有做你认为它做的和不需要的事情。在这种情况下,丢失的代码以某种方式尝试使用单例 DbContext 实例。 -
从普通的旧 EF Core 代码开始,而不是尝试使用“最佳实践”。现在没有人知道发生了什么,除了说“存储库”和“工作单元”类不工作。正确配置的 DbContest 可以正常工作。使用
AddDbContext工作正常。如果您将 DbContext 作为依赖项添加到控制器,它将正常工作,并且仅在您在操作结束时调用SaveChanges一次时才会持久更改。如果您不这样做,所有更改都将被丢弃。这是开箱即用的 U-o-W -
您能解释一下为什么“通用存储库”是反模式吗?如果我有很多存储库,那么不要重复我的代码会很有用。我可以发布哪些代码可以帮助您理解我的问题?
-
为什么你甚至需要一个存储库? DbSet 是存储库。 DbContesxt 是工作单元。为什么要写
AddAsync方法呢?至于您需要发布的代码,是将DbContext实例存储到_context的代码。显然,您不应该使用 Singleton 实例。您可能需要发布完整的 UoW 和操作代码,因为无论该代码做什么,都不是标准或常见的
标签: c# asp.net-core entity-framework-core