How to implement cascading triggers? - parse-platform

I have 2 classes:
Class A: Field1 (string), Field2 (number)
Class B: Field3 (Pointer to Class 1), Field4 (string)
Field4 (Class B) is set to be equal to Field1 (Class A).
Now, in beforeSave trigger for Class A, how to detect which fields in Class A, are pointed to, by fields in other classes (e.g. Field3 in Class B), so that:
a (custom ?) trigger can be executed, or
a function can be run,
to update the dependent fields in Class B (in this case, Field4) ?
Because, if this update in Class A is not detected in the context of Class B, the data in Class B will just fall out of sync!

You can do something like this:
Parse.Cloud.afterSave('ClassA', async ({ original, object }) => {
if (original.get('field1') !== object.get('field1')) {
const query = new Parse.Query('ClassB');
query.equalTo('field3', object);
const objs = await query.find({ useMasterKey: true });
objs.forEach(obj => {
obj.set('field4', object.get('field1'));
});
Parse.Object.saveAll(objs, { useMasterKey: true });
}
});

Related

C#7: How to use tuples in generic methods (LINQ select example)

I have some heavily repeating code, which has always the same structure, just using different columns in a database for accessing it and doing similar stuff
A typical query looks like:
var portfolioIds = context.PortSelMotorSeries
.Select(x => new { x.Id, x.InstallationAltitudeMax })
.ToList();
Now I want to use a generic function for dependency inversion and to pass the selector function as a delegate to the query:
private void ForEachIterate<T1>(Func<MotorSeriesDb, T1> selectorFunc): where T1 : (int Id, double Value)
{
...
var portfolioIds = context.PortSelMotorSeries
.Select(selectorFunct)
.ToList();
...
}
So that I can call the query with my own selector:
ForEachIterate(x => new { Id = x.Id, Value = x.InstallationAltitudeMax });
ForEachIterate(x => new { Id = x.Id, Value = x.TemperatureMax });
Specifying the constraint with "where T1 : (int Id, double Value)" leads to a compiler error CS0701.
Leaving it away leads to other compiler errors.
Is there any way to use tuples in generic functions?
For one thing you're confusing tuples (the (int Id, double Value) thing) with anonymous classes (the new { Id = x.Id, Value = x.TemperatureMax }). They aren't even related, so your code would never work as is.
For another, if all you want is to force the user to output a tuple of some specific type, you can do something like this:
private void ForEachIterate(Func<MotorSeriesDb, (int, double)> selectorFunc)
{
...
var portfolioIds = context.PortSelMotorSeries
.Select(selectorFunct)
.ToList();
...
}
// call like:
ForEachIterate(x => (x.Id, x.InstallationAltitudeMax));
Note that there's nothing generic about your function at all. Which leads me to my third point: you're missing the entire point of Linq. You talk about inversion of control, but you're the one who's inverting it in the wrong direction to begin with.
You already have a construct that allows arbitrary selection: context.PortSelMotorSeries. Simply use Linq to select what you want out of it in the call site and you're done.
If you try this it could works:
private static void ForEachIterate<T1>(Func<MotorSeriesDb, T1> selectorFunc) where T1 : Tuple<int, double>
{
var portfolioIds = context.PortSelMotorSeries
.Select(selectorFunct)
.ToList();
}

Group by query not executing as expected

I have query like this for TheEntity type:
var source = await _repository.Queryable.AsNoTracking()
.Where(Condition1())
.Where(Condition2(params))
.GroupBy(GroupByFunction)
.Select(SelectFunction)
.OrderBy(o => o.Field1)
.ToAsyncEnumerable().ToList();
This query select all records which fulfill conditions: Condition1, Condition2, but does not group them as I expected.
SelectFunction and GroupByFunction looks like below:
private readonly Expression<Func<IGrouping<TheEntityGroupByData, TheEntity>, TheEntitySelectData>> SelectFunction =
e => new TheEntitySelectData()
{
Field1 = e.Key.Field1,
Field2 = e.Key.Field2,
...
FieldN = e.Key.FieldN,
Field(N+1) = e.Sum(x=>x.Field(N+1)),
...
FieldK = e.Sum(x=>x.FieldK),
};
private readonly Expression<Func<TheEntity, TheEntityGroupByData>> GroupByFunction =
e => new TheEntityByData()
{
Field1 = e.Field1,
Field2 = e.Field2,
...
FieldN = e.Key.FieldN,
};
TheEntityGroupByData, TheEntitySelectData are helper DTO/PO_Os types.
I intendent to fire grouping on database rather than server, but this behavior does not work even in server memory.
I use .Net Core 2.0.5 and EntityFrameworkCore 2.0.2.
My question is where is the problem in this approach?
edit - What I mean query not work as I expected is that: If I will have two the same records in db (same by grouping key) that fulfill Condition1 and Condition2, query will return 2 instead of one records.
Filtering conditions looks like below:
private static Expression<Func<TheEntity, bool>> Condition1()
{
return (e) => e.Field1 == SOME_CONSTANT;
}
private static Expression<Func<TheEntity, bool>> Condition2(RequestParam param)
{
Expression<Func<TheEntity, bool>> whereSth;
if (param.some.HasValue)
whereSth = (e) => e.Field2 <= param.some.Value;
else
whereSth = (e) => true;
return whereSth;
}

How to handle cacheing with big nested objects

I have a graphql object that has a bunch of nested object fields like the following:
object{
field1
field2
field3
field4 {
field4.1
field4.2 {
field4.2.1
}
}
field5 {
field5.1{
field 5.1.1
field 5.1.2
}
}
field 6
field 7
}
The issue is that for field4 and field5 there is no unique identifier for them and they are always unique to the object. I don't want it to try to cache these objects and instead just cache the whole object since the child fields are unique to the parent object.
How do I tell me client that I dont want to try and cache these child fields and instead just cache the object as a whole?
I did the following to get around this
const blackList = new Set()
new InMemoryCache({
dataIdFromObject: (o: any) => {
if (o.__typename != null) {
if (cacheBlacklist.has(o.__typename)) {
return null
}
...
}

Distinct by Attribute inside the item on my collection

I have an IEnumerable<MyObject> collection, with N MyObject elements.
MyObject is a class with a Title, a Description and an ID (as string).
I'd like to have my collection with distinct list of MyObject, due to the ID field.
So if 2 MyObject have got the same ID, one should be deleted (don't care which, I need unique ID).
How can I do it with LINQ?
Tried :
myList = myList.GroupBy(o => o.ID);
but seems I need a cast?
You can implement a custom IEqualityComparer<MyObject>. Then you can use Enumerable.Distinct to filter out duplicates.
class DistinctIdComparer : IEqualityComparer<MyObject> {
public bool Equals(MyObject x, MyObject y) {
return x.Id == y.Id;
}
public int GetHashCode(MyObject obj) {
return obj.Id.GetHashCode();
}
}
Now it's simple:
IEnumerable<MyObject> distinct = myObjects.Distinct(new DistinctIdComparer());
Or you can use Enumerable.GroupBy what is even simpler:
distinct = myObjects.GroupBy(o => o.ID)
.Select(g => g.First());
If you wants only unique id then you can try.
var uniqueIds = myObjects.Select(x=>x.ID).Distinct();
Or for Unique ID Objects
List<MyObject> objs = new List<MyObject> ();
myObjects.ForEach(x=>{
if(objs.Find(y=>y.ID == x.ID)== null)
objs.Add(x);
});

Linq to NHibernate - select count problem

Given the classes A and B where
class A
{
string Name;
Ilist<B> BList;
}
class B
{
string Name;
}
With FluentNH mapping, relationship is many-to-many which is HasManyToMany(x => x.B) for A. B has no reference to A. NH version is 2.1.2.4000.
What should be the linq query to select the collection where each row contains B.Name and count of A's containing that B? Result must be the List of anonymous type who has 2 fields: Name and Count. Result also should include all B's, hence it should be outer join.
My intend is to get the result with minimum round-trips to database, possibly in one go.
If you want to do it in Linq in one hit in code, you could do this...
var result = Session.Linq<A>()
.SelectMany(a => a.BList, (a, b) => new { b.Name, A = a.Id })
.ToList()
.GroupBy(x => x.Name)
.Select(x => new { Name = x.Key, Count = x.Count() })
.ToList();
NHibernate.Linq (2.1.2.4000) can't handle a GroupBy after a SelectMany it seems, so the first ToList pulls all the data into memory. This is inefficient -- a SQL count would be better.
Alternatively, you could add a lazy loaded collection to your B class that goes back to A. If you're using a many-to-many table in the middle, that should be easy.
public class B
{
public virtual string Name { get; set; }
public virtual IList<A> AList { get; private set; }
}
Your query simply becomes...
var result = Session.Linq<B>()
.Where(b => b.AList.Count > 0)
.Select(b => new { b.Name, b.AList.Count }
.ToList();
Which produces very efficient SQL from Linq (using a count) and gives the same result.

Resources