Open GoogleCodeExporter opened 8 years ago
I found that value and entityCollection were pointing to the same reference.
When
SetEntityCollectionProperty enumerates value and changes entityCollection by
adding
to it, the error gets thrown. In fact, it seems this iteration is unnecesary
since
the collection appears to be fully populated. However, there may be use cases
where
this is necessary that I am not aware of.
Original comment by mwrock...@gmail.com
on 20 Sep 2009 at 10:19
I hit this on my latest project and dug into it a little more with a simple
test
case. It seems to be that this snippet in the SharpModelBinder.cs class is
where the
failure starts:
private void ReplaceValueProviderWithCustomValueProvider(ModelBindingContext
bindingContext,
PropertyDescriptor propertyDescriptor, Type propertyType, Type
typeOfReplacementValueProvider) {
string valueProviderKey =
CreateSubPropertyName(bindingContext.ModelName,
propertyDescriptor.Name);
ValueProviderResult defaultResult;
bool couldGetDefaultResult =
bindingContext.ValueProvider.TryGetValue(valueProviderKey, out
defaultResult);
if (couldGetDefaultResult) {
ValueProviderResult replacementValueProvider =
CreateReplacementValueProviderOf(typeOfReplacementValueProvider,
propertyType, defaultResult);
bindingContext.ValueProvider.Remove(valueProviderKey);
bindingContext.ValueProvider.Add(valueProviderKey,
replacementValueProvider);
}
}
The TryGetValue call returns false because the valueProviderKey is the name of
the
property on the model but the value provider only contains the indexed values.
Ex.
Model.LineItems versus Model.LineItems[0], Model.LineItems[1], etc. Since the
couldGetDefaultResult variable ends up being false, it never replaces the value
provider so the whole thing blows up later on in the process.
I was able to work around this by changing my view so that the form values
posted for
the entity collection all used the same name as the collection property and
then it
worked correctly. It seems indexing it using array notation is causing the
Sharp
Model Binder to choke.
If my model was:
public class TestViewModel
{
public IList<SomeEntity> SomeEntities { get; set; }
}
This view code failed:
<input name="SomeEntities[0]" id="SomeEntities[0]" />
<input name="SomeEntities[1]" id="SomeEntities[1]" />
<input name="SomeEntities[2]" id="SomeEntities[2]" />
But this view code worked:
<input name="SomeEntities" id="SomeEntities[0]" />
<input name="SomeEntities" id="SomeEntities[1]" />
<input name="SomeEntities" id="SomeEntities[2]" />
Hope this gets resolved soon and that this workaround is helpful for someone.
Original comment by darc...@gmail.com
on 8 Dec 2009 at 6:13
BTW, it seems this workaround only helps in scenarios where you are selecting
multiple
existing entities for a list, not in the scenario where you are
creating/editing
multiple sub-entities since you need to have the [] index notation there.
I'm hitting this on my current project and will likely spend a little bit of
time
trying to figure out how to get it working. Will report back when/if I find a
workaround.
Original comment by darc...@gmail.com
on 10 Dec 2009 at 9:36
After poring over the MVC DefaultModelBinder as well as the SharpModelBinder
and trying to understand
it all, I have been able to put together some changes to the Sharp Model Binder
that fixes this issue
with binding to collections of entities.
What I've basically done is pulled out all the custom value provider code and
implemented it as just a
custom model binder only for entity types (not entity collection types). The
rationale here is that the
default MVC ModelBinder implementation for populating a collection works fine
and will call out to the
custom code for each entity that needs to go into the collection. Also, we only
care about our custom
behavior for existing entities that we are pulling from the DB. I then went
back and added back in all
the code from the SharpModelBinder for setting the protected Id property and
doing all the validation-
related stuff.
Tested scenarios:
1) Controller action taking lists of entities directly
public ActionResult Something(IList<MyEntity> ExistingEntities, IList<MyEntity>
NewEntities)
{ ... }
View Code:
<!-- These are ID values and the list will be populated with entity objects
from the DB -->
<input name="ExistingEntities[0]" value="1" />
<input name="ExistingEntities[1]" value="2" />
<input name="ExistingEntities[2]" value="3" />
<!-- The list will be populated with new entity objects and the Number property
set -->
<input name="NewEntities[0].Number" value="ABC" />
<input name="NewEntities[1].Number" value="DEF" />
<input name="NewEntities[2].Number" value="GHI" />
2) Controller action taking a viewmodel object that contains lists of entities
public ActionResult Something(MyEntityViewModel viewModel)
{ ... }
public class MyEntityViewModel
{
public IList<MyEntity> NewEntities { get; set; }
public IList<MyEntity> ExistingEntities { get; set; }
}
View Code (The same view code from above works as well):
<!-- These are ID values and the list will be populated with entity objects
from the DB -->
<input name="viewModel.ExistingEntities[0]" value="1" />
<input name="viewModel.ExistingEntities[1]" value="2" />
<input name="viewModel.ExistingEntities[2]" value="3" />
<!-- The list will be populated with new entity objects and the Number property
set -->
<input name="viewModel.NewEntities[0].Number" value="ABC" />
<input name="viewModel.NewEntities[1].Number" value="DEF" />
<input name="viewModel.NewEntities[2].Number" value="GHI" />
Hope this helps. I'm going to post a message in the discussion group to see if
Billy has any comments
on these changes.
Original comment by darc...@gmail.com
on 11 Dec 2009 at 2:19
Attachments:
With the changes to the SharpModelBinder for MVC 2, we will have to revisit this
after the 2010 Q1 release
Original comment by alec.whi...@gmail.com
on 23 Feb 2010 at 5:16
Issue fixed in v1.5
Original comment by alec.whi...@gmail.com
on 25 Mar 2010 at 5:00
Original issue reported on code.google.com by
burnwith...@gmail.com
on 16 Sep 2009 at 10:23