当前位置: 首页 > article >正文

Web开发:ABP框架5——入门级别的常见问题和报错解析

目录

一、常见问题

1. Swagger界面找不到接口

2.注释不显示

步骤一:新建xml输出

步骤二:代码引用xml文件

 3.日期格式化带T

4.输出变量格式化(小驼峰->大驼峰)

二、报错解析

1.Swagger界面报错

 2.底层代码调用失败

3.仓储引用失败 

三、通用错误排查方法

1.查控制台程序输出

2.查日志

四、疑难解答

1. 两个仓储的区别

 2.前端传入枚举,让传参更清晰

3.ABP和 Volo.ABP区别

4.ABP框架下实体映射的两种方式

五、开发人员对接口测试流程 

六、EFcore疑难专项

1.主键配置

2.映射失败的几大原因

3.任务中途取消

4.派生类型无法配置密钥

5.实体继承 Entity和继承AuditedAggregateRoot的区别

 6.EFcore如何打印sql

7.EFcore实体和数据库的对接错误


一、常见问题

1. Swagger界面找不到接口

  • 代码问题:WebApi控制器(服务)没有继承ApplicationService
  • 缓存问题:给浏览器清理下缓存,重启VS2022

2.注释不显示

步骤一:新建xml输出

方法一:哪个类库不显示,改对应类库的工程文件

    <GenerateDocumentationFile>true</GenerateDocumentationFile>
    <DocumentationFile>bin\Debug\net6.0\Acme.BookStore.HttpApi.Host.xml</DocumentationFile>

方法二: 对应类库的右键属性设置

 输入框填写的内容应该和工程文件种的一致:

bin\Debug\net6.0\Acme.BookStore.HttpApi.Host.xml

步骤二:代码引用xml文件

        API模块种补上代码,当然也可以直接字符串写死  xmlFile = " Acme.BookStore.HttpApi.Host.xml " ,怎么命名都好,总之,xmlFile这个文件名和上面步骤一设置的文件名一致。

private static void ConfigureSwaggerServices(ServiceConfigurationContext context, IConfiguration configuration)
{
    var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";//"Acme.BookStore.HttpApi.Host.xml"
    var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);

    context.Services.AddAbpSwaggerGenWithOAuth(
        configuration["AuthServer:Authority"],
        new Dictionary<string, string>
        {
                {"BookStore", "BookStore API"}
        },
        options =>
        {
            options.SwaggerDoc("v1", new OpenApiInfo { Title = "BookStore API", Version = "v1" });
            options.DocInclusionPredicate((docName, description) => true);
            options.CustomSchemaIds(type => type.FullName);
            options.IncludeXmlComments(xmlPath); // 添加这一行
        });
}

修改后的效果:

注意:工程文件只需要配置对应的应用层即可!不要再配置Host,否则会覆盖你应用层生成的xml。

 3.日期格式化带T

需求如下,输出的日期带T,我们不需要显示T

代码编写位置 

 加上这个:

Configure<AbpJsonOptions>(options =>
{
    options.DefaultDateTimeFormat = "yyyy-MM-dd HH:mm:ss";
});

如果你想全局配置,那也可以将上述代码加在Program.cs这里,所有模块都会实现这样的效果:

(注意:我觉得日期格式化,虽然上面的方法可以解决问题,但是始终是不够灵活,因为有时候返回出去的是yyyy-MM-dd而不是完整的时间,因此我觉得用tostring方法手动调整,返回字符串出去 或者让前端处理,或许会更好) 

4.输出变量格式化(小驼峰->大驼峰)

方法一:全局配置

builder.Services.AddMvc().AddJsonOptions(options =>
{
    options.JsonSerializerOptions.PropertyNamingPolicy = null;
});

 效果:

方法二:每个字段都用特性配置

例如:


 效果:

二、报错解析

1.Swagger界面报错

错误:Fetch errorInternal Server Error /swagger/v1/swagger.json

方法:查看控制台程序报错情况

可能情况:

  1. WebApi控制器(服务)某个方法使用了public修饰符,但是没有[HTTPGet]或其他请求标识特性,ABP 框架默认将其视为接口,因此会报错。(解决方法:①加上请求特性,用作接口;②或者用private修饰符声明私有方法,供其他接口使用,不作为对外开放接口)
  2. WebApi控制器(服务)出现路由同名现象,引发冲突。

 2.底层代码调用失败

错误:Castle.Proxies.BookAppServiceProxy

原因1:底层代码接口未注入到依赖容器,服务找不到这个底层代码接口

解决方案:底层代码继承ApplicationService或实现ITransientDependency

 原因2:EFcore未设置Dbset,却通过EFcore仓储查表

 解决方案:设置好Dbset即可

3.仓储引用失败 

报错信息:“Acme.BookStore.Books.Book”不能用作泛型类型或方法“IRepository<TEntity, TKey>”中的类型参数“TEntity”。没有从“Acme.BookStore.Books.Book”到“Volo.Abp.Domain.Entities.IEntity<System.Guid>”的隐式引用转换。

 原因:实体类没有继承AuditedAggregateRoot<Guid>或者AggregateRoot<Guid>或者DOEntity,因为IRepository<TEntity, TKey>需要继承自 IEntity<TKey> 接口。

三、通用错误排查方法

1.查控制台程序输出

2.查日志

  • 位置参考:\src\xxxx.HttpApi.Host\Logs

四、疑难解答

1. 两个仓储的区别

        一个指定了主键类型,调用GetAsync(根据id查表)、DeleteAsync(根据id删数据)等方法时,直接传入对应类型的id即可,否则需要传入LINQ的表达式树

private readonly IRepository<Book, Guid> _bookRepository;//await _bookRepository.DeleteAsync(id);
private readonly IRepository<Book> _bookRepository;//await _bookRepository.DeleteAsync(x=>x.Id==Guid.NewGuid());

 2.前端传入枚举,让传参更清晰

//前端传入方式:post请求或者get请求直接传一个枚举值(string) 或者 索引(int) 都可(例如querytype="Grade1",或者querytype=1)

//接收前端的实体:
public class SearchInput
{
   //可以写其他属性
   public StudentEnum querytype { set; get; }
}

//枚举示例:
public enum StudentEnum
{
    Grade1 = 1,
    Grade2 = 2,
    Grade3 = 3
}

//后端可以这样判断:
bool isgrade1 =  input.querytype == StudentEnum.Grade1;// 上述两种入参,都可以输出True

3.ABP和 Volo.ABP区别

        ABP和 Volo.ABP 是两个不同的框架,后者版本更加新,有基于最新的 ASP.NET Core 技术栈且ORM-EFcore采用高版本的。

4.ABP框架下实体映射的两种方式

[Route("api/books")]
public class BookAppService : ApplicationService, IBookAppService
{
    private readonly IBookService _bookService;
    private readonly IObjectMapper _objectMapper;
    public BookAppService(
        IBookService bookService,
        IObjectMapper objectMapper
        )
    {

        _bookService = bookService;
        _objectMapper = objectMapper;
    }

    [Route("getbookbybll")]
    [HttpGet]
    public async Task<List<BookDto>> GetListByBLLAsync()
    {
        List<BookDto> list = await _bookService.GetBooks();//假设有一个服务可以获取List<BookDto>
        List<Book> test1 = ObjectMapper.Map<List<BookDto>,List<Book>>(list);//方案一,底层接口或者WebApi控制器继承ApplicationService,直接使用ObjectMapper(前提:应用层配置好映射关系CreateMap)
        List<Book> test2 = _objectMapper.Map<List<BookDto>,List<Book>>(list);//方案二,注入IObjectMapper使用(前提:应用层配置好映射关系CreateMap)
        return list;
    }

}

五、开发人员对接口测试流程 

  1. 检索条件是否生效
  2. 分页效果(测试第一到第三页)
  3. 比对数据
  4. 查看控制台程序和日志是否存在报错现象

六、EFcore疑难专项

1.主键配置

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<xxxModel>(b => 
    {
        b.ConfigureByConvention();
        // b.HasKey(x => new { x.Id }); // 其实不需要显式指定主键,只要你的实体中含有属性名称为Id的属性,EF Core 会自动识别 Id 为主键(注意不可识别id)
    });
}

        不需要显式指定主键,只要你的实体中含有属性名称为Id的属性,EF Core 会自动识别 Id 为主键(注意不可识别id,是区分大小写的)

2.映射失败的几大原因

  1. 配置问题:Dbcontext写错字段类型,例如NUMBER(8,2)写成了NUMBER(8),如果高级版本采用ConfigureByConvention配置,不存在这个问题。
  2. 入参问题:前端传入和后端接收字段类型不一致,例如Guid和string
  3. 映射关系问题:没有创建CreateMap,导致映射失败(Mapping failed)

3.任务中途取消

报错:A Task was canceled

Update操作:根据传递实体的主键,查不到数据(检查主键是否正确)

4.派生类型无法配置密钥

A key cannot be configured on 'xxxx' because it is a derived type

实体字段配置问题:数据库实体不能继承另一个实体

反例:

public class A 
{


}
public class B : A
{


}

正例:

//抽取公共字段出来,写在Common类中
public class A : Common
{


}
public class B : Common
{


}

5.实体继承 Entity<int>和继承AuditedAggregateRoot<id>的区别

讲直白点:

①仓储查表

        必须继承一个,才能使用下述方式(注入仓储)来通过EFcore查表

private readonly IRepository<Book, Guid> _bookRepository;

②少写字段

        继承Entity<int> ,实体可以少写一个 Id 字段
        继承AuditedAggregateRoot<int>,实体可以少写很多字段例如创建时间、修改时间、操作用户等

③查表拼接

        查表会拼接你这个实体所有的字段,包括继承的,这说明强制要求我们的表主键字段含有Id,否则就会出错。

        不过也可以强制修改,例如我有一个表,继承了Entity<int>:

        查表生成的sql是这样的:

SELECT Id,[pid],[pname] FROM [TestABP].[dbo].[Parent]

         我没有Id字段,就会导致查这张表失败,解决方案二选一如下:

        ①改名,pid改为Id(不区分大小写,改成id Id ID iD都可以)

        ②忽略Id字段,让EFcore拼接查询sql的时候忽略它,以下两个步骤都必不可少,没有主键标记EFcore也会报错:

        builder.Entity<Parent>(b =>
        {
            //b.ToTable(BookStoreConsts.DbTablePrefix + "Books", BookStoreConsts.DbSchema);

            
            b.HasKey(x => x.pid);// 声明本表主键【步骤一】
            b.Ignore(x => x.Id); //忽略继承的主键【步骤二】
            
            b.ConfigureByConvention();// 自动配置基本属性
        });

        说了那么多,建议还是按它们那套标准来:建表必定含有Id字段作为主键,然后实体继承了Entity<int>后就不要重复写id字段了(重复写id字段可以查表,但是EFcore不支持这样映射,还是会报如下的错)。

 6.EFcore如何打印sql

在上下文类加上以下代码即可:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
   optionsBuilder
    // 输出到 VS 输出窗口
    .LogTo(msg => System.Diagnostics.Trace.WriteLine(msg), new[] { Microsoft.EntityFrameworkCore.Diagnostics.RelationalEventId.CommandExecuting });

}

7.EFcore实体和数据库的对接错误

常见错误如下(以下表格情况是在实体设置好dbset情况下进行的):

结果原因解决方案
实体多一个字段报错查表会拼接无关字段,SQLsever报错

1.实体删除无关字段

2.上下文类忽略该字段(二选一)

实体少一个字段正常列表结果没有这个缺失的字段而已
实体字段名一样类型不同报错        查表正常,EFcore转化到实体时异常修改对应字段名的类型(例如把string改为int)
有实体无表报错     查表出错,SQLsever报错建表
有表无实体正常       没有实体=不会查表,不会查表=不会报错

通用解决方法:查表不用EFcore

(吐槽一下:EFcore又难用,拼出来的SQL又复杂,还不如用主流的ORM框架!)


http://www.kler.cn/news/362398.html

相关文章:

  • pdf编辑软件有哪些?方便好用的pdf编辑软件分享
  • 10. 异常处理器
  • 家庭海外仓想爆单,找对思路少走3年弯路
  • 5G NR GSCN计算SSB中心频率MATLAB实现
  • 【Qt】Windows下Qt连接DM数据库
  • 【算法系列-栈与队列】匹配消除系列
  • 信息安全工程师(64)其他恶意代码分析与防护
  • 【Qt】控件——Qt多元素控件、常见的多元素控件、多元素控件的使用、List Widget、Table Widget、Tree Widget
  • pyside6 使用vtk的时候出现页面空洞问题
  • MySQL 日常维护指南:常见任务、频率及问题解决
  • 【C++语言】深入学习C++要修炼的内功
  • 网络工程毕设开题报告汇总
  • 高级 SQL 技巧
  • 6.1 特征值介绍
  • 数据库的查询操作
  • 6、面向对象八股文(长期更新_整理收集_排版未优化_day06_20个
  • volatile 关键字的作用学习
  • 中小企业如何做大做强?
  • Cadence元件A属性和B属性相互覆盖
  • k8s集群安装
  • 2024/10/23 (easycovery密匙激活码为什么这么贵)
  • 调查显示软件供应链攻击增加
  • 知识问答网站毕业设计基于SpringBootSSM框架
  • git tag 用法
  • Spring Boot在线考试系统:JavaWeb技术的应用案例
  • 使用Redisson的布隆过滤器解决缓存穿透问题