Disable global query filters *inside* another global query filter - entity-framework-core

Currently using EF Core 3.1 (although upgrading to EF Core 5 soon, so if this becomes easier in that version, I'm still interested).
I'm implementing some global query filters to restrict access to entity data based on various criteria.
One of the filters operates on a type called "Encounter". An Encounter is linked to a single Person (via foreign key PersonID), but a Person can have many Encounters. The Person record has a navigation property to all linked encounters via Person.Encounters.
The query filter for Encounter is to restrict records based on the value of a particular property on Encounter (call it EncounterType). This works fine if my query filter is something like this:
x => x.EncounterType == "MyType"
However, I need to extend this logic so that an Encounter is allowed/loaded if any encounter linked to the Person meets the criteria.
So, the query filter for Encounter needs to be something like this:
x => x.Person.Encounters.Any(y => y.EncounterType == "MyType")
This does not currently work, because we run into a cycle and a StackOverflowException1; the global query filter for Encounter ends up expanding itself infinitely. (I think it's because we access the Person.Encounters navigation property and evaluate the same Encounter query filter for each encounter in Person.Encounters.)
What I really want to do is to completely disable the global query filter for any navigation properties used in this particular expression. In this scenario, I want to consider all other Encounters linked to the Person, without further filtering.
I know when actually running a query, I can call IgnoreQueryFilters(). I want something like that, but available inside the expression or when adding the query filter with HasQueryFilter().
Is this possible? Is there any other way I can accomplish this with global query filters?
[1] Which, while frustrating, is pretty cool for me...I've never posted a question about an actual stack overflow on StackOverflow :)

Related

In ObjectBox for Flutter, is there a way to compare two properties?

I'm new to using ObjectBox, so I've been trying to do some experimenting with its query system to familarize myself with it. One of the queries I've been unable to do is a query comparing two properties. Ignoring the errors they throw, these are some examples of what I'm looking to do:
// Get objects where first number is bigger than second number
boxA.query(ObjectA_.firstNumber.greaterThan(ObjectA_.secondNumber))
// Get parent objects where one of its children has a specific value from the parent
parentBox.query().linkMany(ParentObject_.children, ChildObject_.name.equals(ParentObject_.favoriteChild));
I know based on this question that it's possible in Java using filters, but I also know that query filters are not in ObjectBox for Dart. One of the workaround I've been testing is querying for one property, getting the values, and using each value to query for the second property. But that becomes unsustainable at even moderately sized amounts of data.
If anyone knows of a "proper" way to do this without the use of Java filters, that would be appreciated. Otherwise, if there's a more performant workaround than the one I came up with, that would be great too.
There is no query filter API for Dart in ObjectBox, because Dart already has the where API.
E.g. for a result list write results.where((a) => a.firstNumber >= a.secondNumber).

foo__icontains QuerySet empty when querying for old Google Cloud Datastore records

I have a model Foo which has a field called bar.
class Foo(models.Model):
bar = models.CharField(max_length=70)
Given an existing instance of Foo whose bar field is set to 'qux', the following query returns an empty QuerySet:
Foo.objects.filter(bar__icontains="qux")
However, if I reference/save the previous instance or I create/save a new Foo, I am able to find it using a similar query.
So, how can I find old, existing records using icontains?
Djangae's documentation makes specific reference to using contains and icontains, but I see no mention of this particular behavior or how to address it. (I do see the index being added to djangaeidx.yaml) I also see nothing in the Migration documentation which makes me think I need to explicitly add an index or similar.
The answer can be found in the 0.9.10 migration guide.
In this situation, you'd need to run something like:
defer_iteration(Foo.objects.all(), Foo.save, _target="your-new-app-version")
in order to add the necessary indexes to existing records.
While this worked, it definitely feels heavy handed to me. I'd be happy to hear from anyone else who might have an alternative solution.

Mongoid: correctly using association callbacks with forms

I have come across a problem which I am struggling to solve elegantly. I am more versed in RDBMSs so the way I am doing things may not be ideal.
What I am doing:
I am having to keep track of items within a HABTM association. Whats more, there is a condition on the count as only items that are 'active' are counted. I have successfully used the association callbacks to track additions and removals from the collection.
The problem:
I am also adding items to the collection via forms by setting the opposite instance's id to the form as a hidden field. This works fine, however the problem is that this adds the opposite instance straight to the collection without invoking the callback (the age old problem).
My Question:
Is there a more elegant way to add add instances to the collection that invokes the callback?
Let me know if you need any more specific examples and I'll happily provide some.
Have you try using the following mongoid3 callbacks?
after_add
after_remove
before_add
before_remove
More information here

Mongo pagination

I have a use case where I need to get list of Objects from mongo based off a query. But, to improve performance I am adding Pagination.
So, for first call I get list of say 10 Objects, in next I need 10 more. But I cannot use offset and pageSize directly because the first 10 objects displayed on the page may have been modified [ deleted ].
Solution is to find Object Id of last object passed and retrieve next 10 objects after that ObjectId.
Please help how to efficiently do it using Morphia mongo.
Using morphia you can do this by the following command.
datastore.find(YourClass.class).field(id).smallerThan(lastId).limit(10).order("-ts");
Since you are querying for retrieving the items after the last retrieved id, you won't be bothered to deal with deleted items.
One thing I have thought up of is that you will have the same problem as with using skip() here unless you intend to change how your interface works.
Using ranged queries like this demands that you use a different kind of interface since it is must harder to detect now exactly what page you are on and how many pages exist in the future, especially if you are doing this to avoid problems with conventional paging.
The default type of interface to arise from this type of paging is merely a infinitely scrolling page, think of YouTube video comments or Facebook wall feed or even Google+. There is no physical pagination or "pages", instead you have a get more button.
This is the type of interface you will need to use to get ranged paging working better.
As for the query #cubbuk gives a good example:
datastore.find(YourClass.class).field(id).smallerThan(lastId).limit(10).order("-ts");
Except it should be greaterThan(lastId) since you want to find everything above that last _id. I would also sort by _id unless you make your OjbectIds sometime before you insert a record, if this is the case then you can use a specific timestamp set on insert instead.

Mapping to legacy MongoDB store

I'm attempting to write up a Yesod app as a replacement for a Ruby JSON service that uses MongoDB on the backend and I'm running into some snags.
the sql=foobar syntax in the models file does not seem too affect which collection Persistent.MongoDB uses. How can I change that?
is there a way to easily configure mongodb (preferably through the yaml file) to be explicitly read only? I'd take more comfort deploying this knowing that there was no possible way the app could overwrite or damage production data.
Is there any way I can get Persistent.MongoDB to ignore fields it doesn't know about? This service only needs a fraction of the fields in the collection in question. In order to keep the code as simple as possible, I'd really like to just map to the fields I care about and have Yesod ignore everything else. Instead it complains that the fields don't match.
How does one go about defining instances for models, such as ToJSON. I'd like to customize how that JSON gets rendered but I get the following error:
Handler/ProductStat.hs:8:10:
Illegal instance declaration for ToJSON Product'
(All instance types must be of the form (T t1 ... tn)
where T is not a synonym.
Use -XTypeSynonymInstances if you want to disable this.)
In the instance declaration forToJSON Product'
1) seems that sql= is not hooked up to mongo. Since sql is already doing this it shouldn't be difficult for Mongo.
2) you can change the function that runs the queries
in persistent/persistent-mongoDB/Database/Persist there is a runPool function of PersistConfig. That gets used in yesod-defaults. We should probably change the loadConfig function to check a readOnly setting
3) I am ok with changing the reorder function to allow for ignoring, although in the future (if MongoDB returns everything in ordeR) that may have performance implications, so ideally you would list the ignored columns.
4) This shouldn't require changes to Persistent. Did you try turning on TypeSynonymInstances ?
I have several other Yesod/Persistent priorities to attend to before these changes- please roll up your sleeves and let me know what help you need making them. I can change 2 & 3 myself fairly soon if you are committed to testing them.