Db4o query: find all objects with ID = {everything in the array}

I saved 30,000 SimpleObjects in my database:

class SimpleObject
{
    public int Id { get; set; }
} 

I want to run a query in DB4O that finds all SimpleObjects with any of the identifiers specified:

public IEnumerable<SimpleObject> GetMatches(int[] matchingIds)
{
     // OH NOOOOOOES! This activates all 30,000 SimpleObjects. TOO SLOW!
     var query = from SimpleObject simple in db
                 join id in matchingIds on simple.Id equals id
                 select simple;
     return query.ToArray();
}  

How to write this query so that DB4O does not activate all 30,000 objects?

+3
source share
4 answers

If you try to run this query using LINQ, it will be run unoptimized (this means that db4o will retrieve all objects of type SimpleObject and delegate the rest to LINQ objects)

n ( id , ) , "Mark Hall".

LINQ (- )

IList<SimpleObject> objs = new List<SimpleObject>();
foreach(var tbf in ids)
{
     var result = from SimpleObject o in db()
               where o.Id = tbf
                  select o;

     if (result.Count == 1)
     {
        objs.Add(result[0]);
     }
}

+2

, DB4O , , . LINQ SODA.

, . , 30000 SimpleObject . , SimpleObjects :

var simpleObjects = db.Query<SimpleObject>(typeof(SimpleObject));

StopWatch, 740 . 100 0 2999. 772 , , . , , , .

. , LINQ DB4O SODA. , SODA , , SODA , 19902 . :

private SimpleObject[] GetSimpleObjectUsingSodaAgainstAProperty(int[] matchingIds, IObjectContainer db)
{
    SimpleObject[] returnValue = new SimpleObject[matchingIds.Length];

    for (int counter = 0; counter < matchingIds.Length; counter++)
    {
        var query = db.Query();
        query.Constrain(typeof(SimpleObject));
        query.Descend("Id").Constrain(matchingIds[counter]);
        IObjectSet queryResult = query.Execute();
        if (queryResult.Count == 1)
            returnValue[counter] = (SimpleObject)queryResult[0];
    }

    return returnValue;
}

, , , , Properties , :

public class SimpleObject
{
    private int _id;

    public int Id { 
        get
        { return _id; }
        set
        { _id = value; }
    }
}

, _id . 91 . :

private SimpleObject[] GetSimpleObjectUsingSodaAgainstAField(int[] matchingIds, IObjectContainer db)
{
    SimpleObject[] returnValue = new SimpleObject[matchingIds.Length];

    for (int counter = 0; counter < matchingIds.Length; counter++)
    {
        var query = db.Query();
        query.Constrain(typeof(SimpleObject));
        query.Descend("_id").Constrain(matchingIds[counter]);
        IObjectSet queryResult = query.Execute();
        if (queryResult.Count == 1)
            returnValue[counter] = (SimpleObject)queryResult[0];
    }

    return returnValue;
}

, , . 60 000 90 000, :

GetAll: 2450 ms
GetWithOriginalCode: 2694 ms
GetWithSODAandProperty: 75373 ms
GetWithSODAandField: 77 ms

, . , , , , . SODA , .

+3

db4o LINQ. DiagnosticToConsole ( ToTrace) IConfiguration.Diagnostic(). AddListener. , .

, Id SimpleObject?

, , :

from SimpleObject simple in db
where matchingIds.Contains(simple.Id)
select simple

See if another query plan gives you.

+2
source

You can "build" a dynamic linq query. For example, an API might look like this:

The first parameter: an expression that indicates which property you are executing. Other parameters: identifier or whatever you are looking for.

 var result1 = db.ObjectByID((SimpleObject t) => t.Id, 42, 77);
 var result2 = db.ObjectByID((SimpleObject t) => t.Id, myIDList);
 var result3 = db.ObjectByID((OtherObject t) => t.Name, "gamlerhart","db4o");

The implementation creates a dynamic query like this:

var result = from SimpleObject t 
  where t.Id = 42 || t.Id==77 ... t.Id == N
  select t

Since everything is combined with OR, you can evaluate directly by indexes. This does not require activation. Implementation Example:

public static class ContainerExtensions{

public static IDb4oLinqQuery<TObjectType> ObjectByID<TObjectType, TIdType>(this IObjectContainer db,
Expression<Func<TObjectType, TIdType>> idPath,
params TIdType[] ids)
{
  if(0==ids.Length)
  {
       return db.Cast<TObjectType>().Where(o=>false);
  }
  var orCondition = BuildOrChain(ids, idPath);
  var whereClause = Expression.Lambda(orCondition, idPath.Parameters.ToArray());
  return db.Cast<TObjectType>().Where((Expression<Func<TObjectType, bool>>) whereClause);
}

private static BinaryExpression BuildOrChain<TIdType, TObjectType>(TIdType[] ids,     Expression<Func<TObjectType, TIdType>> idPath)
{
  var body = idPath.Body;
  var currentExpression = Expression.Equal(body, Expression.Constant(ids.First()));
  foreach (var id in ids.Skip(1))
  {
    currentExpression = Expression.OrElse(currentExpression, Expression.Equal(body,     Expression.Constant(id)));
  }
return currentExpression;
    }

}
+2
source

Source: https://habr.com/ru/post/1722135/


All Articles