Skip to content

修改数据库的操作


// 生成实体变更
dotnet-ef migrations add XXXX

// 其中如果包含外键相关的,就在 XXXX文件中 将Up和Down方法中的外键相关进行删除
// 新创建表的时候一起添加外键应该是没问题的,如果是修改表的时候可能就存在问题

//使用命令行工具
https://learn.microsoft.com/zh-cn/ef/core/cli/dotnet?WT.mc_id=DOP-MVP-5003855#installing-the-tools

// 查看版本
https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql

// 同步到数据库
dotnet-ef database update

// 超过一个dbcontext就需要指定

dotnet-ef migrations add XXXX -c SecondContext

dotnet-ef migrations add XXXX -c DvsContext --framework net6.0

// 通过-v可以查看执行过程以及发生错误的具体error信息
dotnet-ef migrations add XXXX -c DvsContext --framework net6.0 -v

dotnet-ef migrations add InitTask -c DvsContext --framework net8.0 -v

dotnet-ef database update  -c SecondContext

dotnet-ef database update  -c DvsContext --framework net6.0

dotnet-ef database update  -c DvsContext --framework net6.0 -v 

dotnet-ef database update  -c DvsContext --framework net6.0 -v 

dotnet-ef database update -c DvsContext --framework net8.0 -v

---------------2024-08-01------------------------------------
参考链接 https://learn.microsoft.com/zh-tw/ef/core/cli/dotnet
安装命令 dotnet tool install --global dotnet-ef

dotnet ef

dotnet ef migrations add MonitorTaskAnonymous -c DvsContext --framework net6.0 -v

dotnet ef database update -c DvsContext --framework net6.0 -v

// 回滚到上一次的变更
// 列出所有的数据库变更list
dotnet ef migrations list -c DvsContext --framework net6.0 -v

// (如果已经变更到数据了)将数据库变更退回到某个变更
dotnet ef database update 20241114015954_VillageParty111401 -c DvsContext --framework net6.0 -v

// 如果只是生成了迁移文件,还没有
---

// 20231204084647_ModifyHouseholdFiled  从当前的下一个变更生成开始
dotnet-ef migrations script 20241114015954_VillageParty111401  -c DvsContext --framework net6.0 -o migrations_2024_1116.sql

// 上面的生成可能包含日志,可以再加入一个参数--idempotent
// 包含了事物处理保护、版本检查、可重复执行
dotnet-ef migrations script 20241114015954_VillageParty111401  -c DvsContext --framework net6.0  -o migrations_2024_1116-2.sql  --idempotent

api.nuget.ogr/v3/index.json无法访问是因为翻墙的问题

将代理更改为直连即可

linux 服务位置

 // 自定义服务地址
 /usr/lib/systemd/system/dvsv3-datamonitor.service

 [Unit]
  Description=dvsv3-datamonitor
  After=network-online.target
  Wants=network-online.target

  [Service]
  # modify when deploy in prod env
  User=dvs
  Group=dvs

  Type=simple
  ExecStart=/usr/local/dotnet-sdk/dotnet /usr/local/sunlight/dvsv3/dvs-datamonitor/DVS.DataMonitor.Api.dll
  WorkingDirectory=/usr/local/sunlight/dvsv3/dvs-datamonitor

  Restart=always
  RestartSec=1
  StartLimitInterval=0

  [Install]
  WantedBy=multi-user.target



 // 系统服务地址
 /etc/systemd/system


// 设置服务开机自动启动
systemctl enable dvsv3-datamonitor

// 重启服务
systemctl restart dvsv3-datamonitor

// 修改配置文件
systemctl daemon-reload

nginx 配置

// 所在路径
/etc/nginx/conf.d/dvsv3.conf
// 从这个配置文件中也可以找到swagger 配置路径docs的服务

location ~ ^/api/datamonitor/ {
    proxy_pass http://127.0.0.1:12017;
}

修改完毕后nginx -s reload

子系统服务配置文件

/usr/local/sunlight/dvsv3/etc/dvs-datamonitor-appsettings.json
{
    "Urls": "http://*:12017",
    "WorkerId": 8,
    "Serilog": {
        "WriteTo": [
            {},
            {
                "Name": "File",
                "Args": {
                    "path": "/var/log/sunlight/v3/dvs-datamonitor.txt"
                }
            },
            {}
        ]
    }
}

数据导出

// 导出模版
// SELECT * FROM Template;

// 异步任务执行装填
select * from AsyncTask s order by s.CreatedAt desc ;

public enum AsyncTaskState
{
    待处理 = 0,
    处理中 = 1,
    处理完成 = 2,
    失败 = 9
}

 select * from `Options`  

 key: storageoptions:path  是文件上传的路径地址

服务器上log.txt日志文件存放路径

/var/log/sunlight/v3

linux下nginx安装

  • 2022-05-11-linux

区域同步

之前使用的是  BasicArea
SELECT  SUM(c.total) total,SUM(c.tobeSubmitted) tobeSubmitted, SUM(c.submitted)  submitted 
FROM  CollectDataHouseholdSummary c 
 where c.type=2 and c.areaid in (select id from BasicArea t where t.IdSequences like @areaId )  


现在 BasicAreaEx
SELECT  SUM(c.total) total,SUM(c.tobeSubmitted) tobeSubmitted, SUM(c.submitted)  submitted 
FROM  CollectDataHouseholdSummary c 
 where c.type=3 and c.areaid in (select t.RegionId from BasicAreaEx t where t.RegionIdSequences like @areaid )

修改表编码

 ALTER TABLE BasicAreaEx CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;

mysql数据库操作

// 展示数据库列表
SHOW DATABASES;

mysql执行数据同步时有可能有数据表访问权限的问题

判断枚举是否存在

            //if (!Enum.IsDefined(typeof(TaskType), model.TaskType))
            //{
            //    throw new ErrorCodeException(-1, "传入的任务类型不存在");
            //}
            //else
            //{
            //    spec.Query.Where(item => item.TaskType == model.TaskType);
            //}

将EFCore IDbContextTransaction转换为 Mysql驱动下 DbTransaction

    public static DbTransaction GetDbTransaction(this IDbContextTransaction source)
    {
        return (source as IInfrastructure<DbTransaction>).Instance;
    }

事务里面如果有创建表结构的则不会跟随事务

数据库菜单更新

etc/dvs-systemservice-appsettings.json 中的MenuSeedData 设置为true


// systemctl restart dvsv3-systemservice
// 则启动服务的时候就会初始化更新菜单
// 更新菜单的规则:code相等则update,code不相等则insert,code不存在则不操作

// 通过接口将数据初始化到json文件中
// 接口要在root用户下才能执行
api/basic/Menu/seed

// 执行完接口后,将接口返回数据的data,也就是菜单数组拷贝到项目中
DVS.Basic/Templates/Menu.json

// 提交代码后,通过流水线进行自动部署

//指定某个服务进行设置最上面的参数即可

定时任务

```
// 定时任务存在于dvsv3-systemservice服务中

// dvs-systemservice-appsettings.json可以配置定时任务的开启时间周期

// ScheduleTaskOptions.cs 以及可以直接在代码中设置默认的时间和周期 

// 通过代码 AddCronServices开启

// 查看所有程序集中的class 继承了 CronScheduleService的定时任务

// 通过单例模式注册
services.Add(new ServiceDescriptor(typeof(IHostedService), a, ServiceLifetime.Singleton));


// 继承了IHostedService ,则相当于后台任务。通过依赖注入注册之后便会在后台运行了

// 然后 重写ExecuteAsync, 这个服务中的ExecuteAsync 方法会一直执行
```

rabbitmq 异步任务处理

  // 首先在Program.cs中注册调用 builder.Services.InitServices
  
  // 其中 通过services.AddDistributedEventBus(configuration);

  // 实现读取配置文件中的rabbitmq配置信息
  // 以及通过依赖注册将RabbitMQEventPublisher 发布者和 RabbitMQEventSubscriber 消费者注册到容器中

  //将所有的处理事件通过 services.AddEventHandlers(); 注入容器中

  // rabbitmq 异步任务主要都在dvsv3-systemservice服务中进行处理 
  // 通过app.InitApp(..,,,,onlyGlobalEvent: false) 
  // onlyGlobalEvent: false 处理事件
  // 通过 app.UseDistributedEventBus(onlyGlobalEvent); 中的 subscriber.Subscribe(); 消费者订阅事件

应急发布逻辑处理

// 保存时写入到VillageMessage表中
// 保存的最后发布RabbitMQ 事件

// 发布事件
eventPublisher.Publish(new VillageMessageChangedEvent()
{
    MessageId = message.Id,
    MessageType = message.MessageType,
    RegionIds = message.PublishRegionIds,
    Tags = message.PopulationTag
});

// 通过VillageMessageChangedEvent 找到消费者的处理事件 VillageMessageEventHandler

// VillageMessageEventHandler中的HandleAsync方法中处理逻辑

// 逻辑包括:
// 插入MessageRegions数据,根据VillageMessage中发布范围RegionIds
// 然后根据RegionsIds 数组中的每一个RegionId 
// 通过RegionId 来查找符合条件的人员的UserId
// 然后批量写入到VillageMessagePushRecord(写入状态为未推送)
// 最终统计消息发送的总人数,更新到VillageMessage表中

//OK OK OK
//现在相当于知道要推送的数据了,开始通过定时任务进行推送
//找到定时推送任务:VillagePushMessageSchedule

// 每次循环最多发送100条
// 循环中的逻辑如下:
// 查询出未推送的记录(还加上了推送时间)
// 将条记录设置为(推送中)
// 调用IMessageService.SendAsync真正的推送消息
// 推送成功后,将推送状态设置为(已推送)
// 如果中间出现异常,则将推送状态设置为(推送失败)

定义微信消息

  • MessageDefine 消息定义表数据
  {
    "Code": "emergency_response_message",
    "Name": "应急发布消息",
    "RedirectUri": "package/szxc/pages/emergency-release/detail/msg?id={MessageId}",
    "Fields": {
      "MessageId": "消息Id",
      "Title": "标题",
      "PublishDate": "发布时间"
    }
  },
  • 模板表中类型Template ContentType
    /// <summary>
    /// 模板内容类型
    /// </summary>
    public enum TemplateContentType
    {
        文本 = 0,   // 短信模板
        文件 = 1,   // 导出和导入模板
        小程序消息模板 = 2,
        公众号消息模板 = 3,
    }

rabbitmq在项目中的使用

// 整体官方文档使用介绍
https://www.rabbitmq.com/dotnet-api-guide.html



// 初始化rabbitmq配置
builder.Services.InitServices 中的

// 添加rabbitmq的配置,并注册发布者和消费者
services.AddDistributedEventBus(configuration);

// 注册EventHandlers到DI容器中
services.AddEventHandlers();

// 例子:应急发布
// Dvs.Basic.Api中 VillageNotifyController SaveAsync方法

// 发布事件
eventPublisher.Publish(new VillageMessageChangedEvent()
{
    MessageId = message.Id,
    MessageType = message.MessageType,
    RegionIds = message.PublishRegionIds,
    Tags = message.PopulationTag
});

// 发布事件的参数,例如数据实体VillageMessageChangedEvent 要继承 EventBase


// 消费者的Consumer继承IBasicConsumer接口,消息会在到达时自动传递,而不必主动请求。
// https://www.rabbitmq.com/dotnet-api-guide.html#consuming

// 异步调度实现的Comsumer要继承IAsyncBasicConsumer接口
// https://www.rabbitmq.com/dotnet-api-guide.html#consuming-async
// 同时要将 ConnectionFactory.DispatchConsumersAsync 属性设置为 true