Reputation: 238
Example
Have a look at the following code:
private void DeDuplicateOrganisations()
{
var profileOrgs = _organisations.Where(o => o.ExistsInProfile).ToList();
var kvkOrgs = _organisations.Where(o => !o.ExistsInProfile).ToList();
profileOrgs.ForEach(o =>
{
var duplicate = kvkOrgs.FirstOrDefault(k => k.KvK == o.KvK || k.Title == o.Title);
if (duplicate != null)
{
o.CompanyInfoOrganisation = duplicate.CompanyInfoOrganisation;
o.ExistsInBoth = true;
kvkOrgs.Remove(duplicate);
}
});
_organisations = profileOrgs.Concat(kvkOrgs).OrderBy(o => o.Title).ToList();
}
In this example the property CompanyInfoOrganisation
(simply a get; set; property) is copied when an organisation is considered a duplicate. This all works as expected, duplicates are nicely deduplicated.
Also this is true inside this message:
_organisations.First(o => o.ExistsInBoth).CompanyInfoOrganisation != null;
Problem
Now I bind the _organisations
list to a listbox
lbxCompanies.DataSource = null;
lbxCompanies.DataSource = _organisations;
lbxCompanies.DisplayMember = "Title";
lbxCompanies.SelectedIndex = -1;
and later on get the selected value:
var org = lbxCompanies.SelectedValue as Organisation;
gbxCompanyInfo.Visible = org != null;
if (gbxCompanyInfo.Visible)
if (org.CompanyInfoOrganisation != null)
// NEVER GETS HERE (but gbxComanpyInfo is visible)
If I try to read the CompanyInfoOrganisation
property I always get null while I know the property was set.
Question
What is happening here? How come the property reference is destroyed? How can I prevent this from happening?
Upvotes: 3
Views: 1273
Reputation: 238
The problem was I used string.Join()
to show the values, and the first value to join was null (which is really annoying), resulting in an empty string, leaving me thinking the property was null. However it turned out the property was not null, but has a perfectly valid reference to the object needed. Using the debugger with a little more care would have saved me an hour or so...
Sorry!
Upvotes: 0
Reputation: 4717
It might have to do with capturing of variables inside the lambda. Try substituting the .ForEach to a regular foreach(). Or maybe the CompanyInfoOrganisation in duplicate was null to begin with.
Upvotes: 0
Reputation: 50728
When you load the data, load the CompanyInfoOrganisation property along with the root entity; that way it will be already loaded into memory. If using LINQ to SQL, you load via DataLoadOptions, and pass this to the context. If using Entity Framework, you use the Include method in the LINQ query.
Upvotes: 0
Reputation: 37533
The reference you're using only has immediate scope and as soon as the query ends it exits scope and your reference disappears. So when you bind later, the reference is exactly right -- null.
profileOrgs.ForEach(o =>
{
// Right here -- var duplicate has scope ONLY within your query.
// As soon as the query is executed it leaves scope and the reference
// pointer will be null
var duplicate = kvkOrgs.FirstOrDefault(k => k.KvK == o.KvK || k.Title == o.Title);
if (duplicate != null)
{
o.CompanyInfoOrganisation = duplicate.CompanyInfoOrganisation;
o.ExistsInBoth = true;
kvkOrgs.Remove(duplicate);
}
});
Because you're using a class, you need to perform a deep MemberwiseClone on it to get a NEW copy of the object:
o.CompanyInfoOrganisation = (YourInfoType)duplicate.CompanyInfoOrganisation.MemberwiseClone();
Upvotes: 4