MongoDB使用IgnoreExtraElementsConvention解决字段不匹配错误

MongoDB使用IgnoreExtraElementsConvention解决字段不匹配错误

问题现象

在多个子系统项目访问同一个MongoDB的应用场景中,有时候会出现一个子系统给Collection的实体类增加了字段,导致别的子系统查询数据库出错的情况。

新建Blazor Server项目MyWeb1,修改一下WeatherForecast,增加Id字段,可以作为实体类保存到数据库。

 

public class WeatherForecast
{
    public string Id { get; set; } = Guid.NewGuid().ToString();

    public DateTimeOffset Date { get; set; }

    public int TemperatureC { get; set; }

    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);

    public string? Summary { get; set; }
}

 

在项目中NuGet安装MongoDB驱动

    <PackageReference Include="MongoDB.Driver" Version="3.3.0" />

 

appsettings.json填写数据库连接字符串

  "ConnectionStrings": {

    "MongoDb": "mongodb://localhost:27017/"

  }

 

WeatherForecastService代码改一下,从数据库查询天气记录。

 

using MongoDB.Driver;
using MongoDB.Driver.Linq;

public class WeatherForecastService
{
    private readonly MongoClient _mongoDbClient = null;
    private readonly IConfiguration _configuration;

    public WeatherForecastService(IConfiguration configuration)
    {
        _configuration = configuration;
        _mongoDbClient = new MongoClient(_configuration.GetConnectionString("MongoDb"));
    }

    private static readonly string[] Summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    public async Task<WeatherForecast[]> GetForecastAsync(DateTimeOffset startDate)
    {
        var db = _mongoDbClient.GetDatabase("WeatherDb");

        var collection = db.GetCollection<WeatherForecast>("WeatherForecast");

        var items = await collection.AsQueryable().OrderByDescending(x => x.Date).ToListAsync();

        if (items.Count == 0)
        {
            items = Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = startDate.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)]
            }).ToList();

            await collection.InsertManyAsync(items);
        }

        return items.ToArray();
    }
}

 

运行MyWeb1项目,查看天气预报,可以看到数据库中增加WeatherForecast集合,有5条记录。

 

新建Blazor Server项目MyWeb2,修改一下WeatherForecast,增加Id字段,并且增加一个湿度字段Humidity

 

public class WeatherForecast
{
    public string Id { get; set; } = Guid.NewGuid().ToString();

    public DateTimeOffset Date { get; set; }

    public int TemperatureC { get; set; }

    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);

    public string? Summary { get; set; }

    /// <summary>
    /// 湿度
    /// </summary>
    public int Humidity { get; set; }
}

 

WeatherForecastService代码改一下,从数据库查询天气记录,并且如果不足10条记录,就增加5条带有湿度字段的记录。

 

public class WeatherForecastService
{
    private readonly MongoClient _mongoDbClient = null;
    private readonly IConfiguration _configuration;

    public WeatherForecastService(IConfiguration configuration)
    {
        _configuration = configuration;
        _mongoDbClient = new MongoClient(_configuration.GetConnectionString("MongoDb"));
    }

    private static readonly string[] Summaries = new[]
    {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };

    public async Task<WeatherForecast[]> GetForecastAsync(DateTimeOffset startDate)
    {
        var db = _mongoDbClient.GetDatabase("WeatherDb");

        var collection = db.GetCollection<WeatherForecast>("WeatherForecast");

        var items = await collection.AsQueryable().OrderByDescending(x => x.Date).ToListAsync();

        if (items.Count < 10)
        {
            items = Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = startDate.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)],
                Humidity = Random.Shared.Next(0, 100)
            }).ToList();

            await collection.InsertManyAsync(items);
        }

        return items.ToArray();
    }
}

 

运行MyWeb2项目,查看天气预报,可以看到数据库中WeatherForecast集合有10条记录了,并且有5条记录是带有湿度Humidity字段的。

 

然后,再运行MyWeb1项目,查看天气预报,报错字段不匹配。

System.FormatException: Element 'Humidity' does not match any field or property of class WeatherForecast.

 

解决方案

MyWeb1项目的WeatherForecastService注册IgnoreExtraElementsConvention,在反序列化记录时,忽略实体类中未定义的字段。

 

    public WeatherForecastService(IConfiguration configuration)
    {
        _configuration = configuration;
        _mongoDbClient = new MongoClient(_configuration.GetConnectionString("MongoDb"));

        var ignoreExtraElementsConvention = new ConventionPack { new IgnoreExtraElementsConvention(true) };
        ConventionRegistry.Register("IgnoreExtraElements", ignoreExtraElementsConvention, _ => true);

 

再运行MyWeb1项目,查看天气预报,没有报错了。

为了避免出现这个错误,需要给所有访问同一个MongoDB的子系统项目,都加上这个IgnoreExtraElementsConvention。每个子系统项目在升级实体类的时候,严格遵从只增不改不删的原则,就不会影响其他已上线子系统的运行。

 

posted on 2025-03-31 21:24  SunnyTrudeau  阅读(25)  评论(0)    收藏  举报