-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow suppressing association key is nil
warning when preloading data
#4584
base: master
Are you sure you want to change the base?
Conversation
Hi @tomconroy , Could you let me know if I understand your situation. Do you want to do this:
|
It looks to me like you want to reverse your operations. First preload and then cast assoc. But I'm not confident I'm understanding your situation properly. |
We are certainly preloading before cast. The key thing is the |
Thanks. I think it's starting to become a bit clearer to me. In regards to this:
What would be the reason for trying to do nested preloads on new children? It seems they are not persisted so the preload would never return anything. Or do I misunderstand? p.s. The reason I am poking around with questions is just so I can understand whether what you want to do below is the right way forward or if you are trying to do something that already has a correct solution
|
I see why it's confusing, maybe this illustrates more clearly? struct = %MyStruct{
children: [%Child{
id: nil,
nested_child_id: 123,
nested_child: %Ecto.Association.NotLoaded{}
}]
}
preloaded_struct = Repo.preload(struct, [children: :nested_child]
preloaded_struct.children |> Enum.map(fn child -> child.nested_child.some_key end)
If we preload this with force: true, the children are going to be reloaded from the db. But we want preload to keep the existing loaded assocs, and only load ones that are |
This is supposed to be the default behaviour. So I think there must be something a bit different between your situation and the test in this PR. Maybe I can explain why the behaviour in the PR happens and you can let me know if it makes sense parent = %MySchema{id: nil, children: [%MySchemaChild{a: "child1"}, %MySchemaChild{a: "child2"}]}
log = ExUnit.CaptureLog.capture_log(fn ->
TestRepo.preload(parent, :children)
end) The reason this has the warning is because |
Yes I understand that, in our case the struct is created through the The |
So the issue is that you do not want to load the data from the database but you still want to preload onto the struct? |
I want to keep the existing behavior (only load |
I think we are talking past each other. |
Sorry, I use "loaded" to mean more narrowly "a value is that not Lines 575 to 578 in 2e66ee8
|
Thanks for the clarification. So I think we are back to my original question:
When I say "new children" above you can think of it as: What is your use case for trying to preload on a struct that has not been persisted yet (does not have an id)? I'm not sure if this is a flow that is supposed to be supported. But I am really trying to understand just so I am not brushing it off. |
I mentioned our use-case in the original post
I can elaborate on what I mean: our This is one of a few different cases where we're doing this. We're also (e.g.) calculating discounts as order_items change, based on the subtotal of the order_items. The function that calculates the subtotal is expecting plain structs, not changesets. (FWIW, I used to have the logic in two places, one that calculates using structs, and one using changesets, but it's much better to have just one of these...) |
This thread popped up while I was researching a related issue. I have a function that abstracts some logic that works on a changeset. It requires access to associated data so it needs to ensure the changeset's data has been preloaded. I was attempting to use |
@tfwright definitely related! Before arriving at |
Thanks. I will try to abstract/simplify what you wrote here. Can you let me know if this is accurate: You are creating some new entities, and these entities are associated to something like a configuration table. And you want to use the values in that configuration table to calculate other values in the entity before persisting it? |
That's accurate! That entity (the order item) has a changeset that casts the user's selections for the configuration, then we take the values from the configuration's associations to put calculated values on the entity. |
And just want to make sure: you need to preload from the parent struct? It wouldn’t make sense to preload directly from the children? Because that would also get rid of the warning. Besides the above I can’t think of another way to solve your problem. So if you cant do the above I think this change is ok. Just want to see what @josevalim thinks in case he knows a reason not to do it. Also to see his opinion if he is concerned we will have to allow finer granularity than Boolean in the future |
Well, the |
Got it. Makes sense to me! I want to wait for Jose before going ahead with the merge. I want to be consistent with whatever policy on warning suppression he thinks is best or has been in place in the past. The reason is because we have multiple warnings and maybe all of them have situations where it makes sense to suppress them or conditionally suppress them. This can snowball if we are not careful, so just want to make sure we are moving forward in a way that let's use maintain our sanity/consistency. |
Sometimes we want to preload data inside a changeset. (In our case, snapshotting values like "price" in an order item from product selections)
The data after apply_changes may have new children (with
id: nil
) like below.Currently with the code above we get a warning message:
We don't want to preload it with
force: true
in this case, because the data is changing and we don't want to override it, we just want a way to suppress this warning.