dj-nitehawk / MongoDB.Entities

A data access library for MongoDB with an elegant api, LINQ support and built-in entity relationship management
https://mongodb-entities.com
MIT License
547 stars 70 forks source link

DB.SaveAsync Error : Must contain at least 1 request #192

Closed li-zheng-hao closed 1 year ago

li-zheng-hao commented 1 year ago
[Fact]
public async Task Save()
{
    IEnumerable<CNCPartCost> data = new List<CNCPartCost>()
    {
        new CNCPartCost(){PartName = "1"},
        new CNCPartCost(){PartName = "2"}
    };
    data=data.DistinctByEx(it => it.PartName);
    await DB.SaveAsync(data);
}

public static IEnumerable<TSource> DistinctByEx<TSource, TKey>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector)
{
    HashSet<TKey> hash = new HashSet<TKey>();
    return source.Where<TSource>((Func<TSource, bool>) (p => hash.Add(keySelector(p))));
}

error info:

System.ArgumentException
Must contain at least 1 request. (Parameter 'requests')
   at MongoDB.Driver.MongoCollectionImpl`1.BulkWriteAsync(IClientSessionHandle session, IEnumerable`1 requests, BulkWriteOptions options, CancellationToken cancellationToken)
   at MongoDB.Driver.MongoCollectionImpl`1.UsingImplicitSessionAsync[TResult](Func`2 funcAsync, CancellationToken cancellationToken)

if i use tolist , then it works fine:

data=data.DistinctByEx(it => it.PartName).ToList();
li-zheng-hao commented 1 year ago

i see this code in SaveAsync:

var models = new List<WriteModel<T>>(entities.Count());
foreach (var ent in entities)
{
    if (PrepAndCheckIfInsert(ent))
    {
        models.Add(new InsertOneModel<T>(ent));
    }
    else
    {
        models.Add(new ReplaceOneModel<T>(
            filter: Builders<T>.Filter.Eq(e => e.ID, ent.ID),
            replacement: ent)
        { IsUpsert = true });
    }
}
return session == null
       ? Collection<T>().BulkWriteAsync(models, unOrdBlkOpts, cancellation)
       : Collection<T>().BulkWriteAsync(session, models, unOrdBlkOpts, cancellation);

entities.Count() changed the location of iterator, then the later for loops can't read the data

li-zheng-hao commented 1 year ago

I debugged with dnspy and found that the iterator could not satisfy the predicate condition after taking the value...

I don't know why, but this is not a MongoDB.Entities error, so I decided to close this issue

List<int> arr=new List<int>();
arr.AddRange(new []{1,2,3});
var res=arr.DistinctBy(it => it);
var cout=res.Count();
foreach (var re in res)
{
    Console.Out.WriteLine("re:"+re);
}

Console.Out.WriteLine("1");
public static class Test
{
    public static IEnumerable<TSource> DistinctBy<TSource, TKey>(
        this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector)
    {
        HashSet<TKey> hash = new HashSet<TKey>();
        return source.Where<TSource>((Func<TSource, bool>) (p => hash.Add(keySelector(p))));
    }
}

image

li-zheng-hao commented 1 year ago

The cause of the problem has been found : https://github.com/ldqk/Masuit.Tools/issues/77