C
C#•this hour
eli

Contains returning False despite same hashcode and Equals returning true

if (!product.QcPhotoSets.Contains(qcPhotoSet))
{
var existingQcPhotoSet = product.QcPhotoSets.FirstOrDefault(q => q.Equals(qcPhotoSet));

if (existingQcPhotoSet != null)
{
_logger.LogInformation("Existing QcPhotoSet {QcPhotoSet} already exists", existingQcPhotoSet);
_logger.LogInformation("Existing hashcode {ExistingHashCode} New hashcode {NewHashCode}, {Equal}", existingQcPhotoSet.GetHashCode(), qcPhotoSet.GetHashCode(), existingQcPhotoSet.Equals(qcPhotoSet));

}

_logger.LogInformation("Adding new QcPhotoSet {QcPhotoSet}", qcPhotoSet);
product.QcPhotoSets.Add(qcPhotoSet); // If it doesn't exist, add it
hasChanged = true;
}
if (!product.QcPhotoSets.Contains(qcPhotoSet))
{
var existingQcPhotoSet = product.QcPhotoSets.FirstOrDefault(q => q.Equals(qcPhotoSet));

if (existingQcPhotoSet != null)
{
_logger.LogInformation("Existing QcPhotoSet {QcPhotoSet} already exists", existingQcPhotoSet);
_logger.LogInformation("Existing hashcode {ExistingHashCode} New hashcode {NewHashCode}, {Equal}", existingQcPhotoSet.GetHashCode(), qcPhotoSet.GetHashCode(), existingQcPhotoSet.Equals(qcPhotoSet));

}

_logger.LogInformation("Adding new QcPhotoSet {QcPhotoSet}", qcPhotoSet);
product.QcPhotoSets.Add(qcPhotoSet); // If it doesn't exist, add it
hasChanged = true;
}
In my log output: Existing hashcode 170042874 New hashcode 170042874, True My classes: (Have removed irellevant fields)
public class QcPhotoSet
{
[Required] public ISet<QcPhoto> QcPhotos { get; set; } = new HashSet<QcPhoto>();

protected bool Equals(QcPhotoSet other)
{
return QcPhotos.SetEquals(other.QcPhotos);
}

public override bool Equals(object? obj)
{
if (obj is null) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((QcPhotoSet)obj);
}

public override int GetHashCode()
{
// Start with the hash of Source
var hash = (int)Source.GetHashCode();

// XOR all photo hash codes together
// XOR is commutative, so order doesn't matter
foreach (var photo in QcPhotos)
{
hash ^= photo.GetHashCode();
}

return hash;
}

public override string ToString()
{
return $"{Source} Qc Photos: ({string.Join(", ", QcPhotos)})";
}
}
public class QcPhotoSet
{
[Required] public ISet<QcPhoto> QcPhotos { get; set; } = new HashSet<QcPhoto>();

protected bool Equals(QcPhotoSet other)
{
return QcPhotos.SetEquals(other.QcPhotos);
}

public override bool Equals(object? obj)
{
if (obj is null) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((QcPhotoSet)obj);
}

public override int GetHashCode()
{
// Start with the hash of Source
var hash = (int)Source.GetHashCode();

// XOR all photo hash codes together
// XOR is commutative, so order doesn't matter
foreach (var photo in QcPhotos)
{
hash ^= photo.GetHashCode();
}

return hash;
}

public override string ToString()
{
return $"{Source} Qc Photos: ({string.Join(", ", QcPhotos)})";
}
}
public class QcPhoto
{
[Required] public required Uri OriginalPhotoUrl { get; init; }

protected bool Equals(QcPhoto other)
{
return OriginalPhotoUrl.ToString().Equals(other.OriginalPhotoUrl.ToString());
}

public override bool Equals(object? obj)
{
if (obj is null) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((QcPhoto)obj);
}

public override int GetHashCode()
{
return OriginalPhotoUrl.GetHashCode();
}
}
public class QcPhoto
{
[Required] public required Uri OriginalPhotoUrl { get; init; }

protected bool Equals(QcPhoto other)
{
return OriginalPhotoUrl.ToString().Equals(other.OriginalPhotoUrl.ToString());
}

public override bool Equals(object? obj)
{
if (obj is null) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((QcPhoto)obj);
}

public override int GetHashCode()
{
return OriginalPhotoUrl.GetHashCode();
}
}
21 Replies
eli
eliOP•this hour
I would expect Contains to return True if the hashcodes match and equals returns true
Pobiega
Pobiega•this hour
consider implementing IEquatable<QcPhotoSet> then it should work and why are your equals methods protected? that could also be it tbh
eli
eliOP•this hour
the public one is calling the protected one if it's the right type that's just how rider generates them
using System.ComponentModel.DataAnnotations;

namespace findsly_api.Models;

public class QcPhoto: IEquatable<QcPhoto>
{
[Key]
public Guid Id { get; set; }

[Required] public required Uri OriginalPhotoUrl { get; init; }

[Required] public required QcPhotoSet QcPhotoSet { get; set; }

[Required] public ProcessingStatus ProcessingStatus { get; set; } = ProcessingStatus.Pending;
public DateTime? TimeProcessingStarted { get; set; }

public bool Equals(QcPhoto? other)
{
if (other is null) return false;

return OriginalPhotoUrl.ToString().Equals(other.OriginalPhotoUrl.ToString());
}

public override bool Equals(object? obj)
{
if (obj is null) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((QcPhoto)obj);
}

public override int GetHashCode()
{
return OriginalPhotoUrl.GetHashCode();
}

public override string ToString()
{
return OriginalPhotoUrl.ToString();
}
}

public enum ProcessingStatus
{
Pending,
Processing,
Processed,
Failed
}
using System.ComponentModel.DataAnnotations;

namespace findsly_api.Models;

public class QcPhoto: IEquatable<QcPhoto>
{
[Key]
public Guid Id { get; set; }

[Required] public required Uri OriginalPhotoUrl { get; init; }

[Required] public required QcPhotoSet QcPhotoSet { get; set; }

[Required] public ProcessingStatus ProcessingStatus { get; set; } = ProcessingStatus.Pending;
public DateTime? TimeProcessingStarted { get; set; }

public bool Equals(QcPhoto? other)
{
if (other is null) return false;

return OriginalPhotoUrl.ToString().Equals(other.OriginalPhotoUrl.ToString());
}

public override bool Equals(object? obj)
{
if (obj is null) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((QcPhoto)obj);
}

public override int GetHashCode()
{
return OriginalPhotoUrl.GetHashCode();
}

public override string ToString()
{
return OriginalPhotoUrl.ToString();
}
}

public enum ProcessingStatus
{
Pending,
Processing,
Processed,
Failed
}
I tried this and it didn't work
Pobiega
Pobiega•this hour
just so I can try and reproduce this, what type is product.QcPhotoSets?
eli
eliOP•this hour
[Required] public ISet<QcPhotoSet> QcPhotoSets { get; set; } = new HashSet<QcPhotoSet>(); Although give me a second to check that cause Product is coming from EF so maybe it changes the type of that when it returns it from DB Just checked the type at runtime and it's still a hashet My theory was that EF was doing some weird shit and using it's own ISet implementation where Contains doesn't work properly but I guess not I have lazy loading and shit disabled
[Fact]
public void Contains_ShouldReturnTrue_WhenQcPhotoSetsAreEqual()
{
// Arrange
var product = ModelFactory.CreateProduct();

var qcPhotoSet1 = new QcPhotoSet
{
Product = product,
Source = QcPhotoSource.Sugargoo,
};

var qcPhotoSet2 = new QcPhotoSet
{
Product = product,
Source = QcPhotoSource.Sugargoo,
};

var qcPhotoSet3 = ModelFactory.CreateQcPhotoSet(product, 10);
var qcPhotoSet4 = ModelFactory.CreateQcPhotoSet(product, 10);
var qcPhotoSet5 = ModelFactory.CreateQcPhotoSet(product, 10);

qcPhotoSet1.QcPhotos.Add(
ModelFactory.CreateQcPhoto(qcPhotoSet1,
"https://gooles.oss-cn-hongkong.aliyuncs.com/21tr902otw8sph2i0wh599tews07it5huhosduifpq0g6www3f7Tw9UfUG74rphD504G5QhrU654Ty9GED4D2OfrU9w88h9Qsf09.jpg")
);
qcPhotoSet1.QcPhotos.Add(
ModelFactory.CreateQcPhoto(qcPhotoSet1,
"https://gooles.oss-cn-hongkong.aliyuncs.com/74ogtrt934o2w3te9g8gsfwta2q98uui7sdu9fydfi4a21216p4UE4Ef741p0A825pOA095rfsG9wQyO0A2h8hif0DQE97rOE119.jpg")
);
qcPhotoSet1.QcPhotos.Add(
ModelFactory.CreateQcPhoto(qcPhotoSet1,
"https://gooles.oss-cn-hongkong.aliyuncs.com/egt18rtdr4hqddt4494euy2q37p59pid3ra3f1dirdhugat14u3ffs6y9h7s5yfAA62AwA3Dff9UwfQOE9AsyQAUUAsA79p477U7.jpg")
);
qcPhotoSet1.QcPhotos.Add(
ModelFactory.CreateQcPhoto(qcPhotoSet1,
"https://gooles.oss-cn-hongkong.aliyuncs.com/69fh36i47rt08ytp9o97u26wgrrroahif8oyfr69hydwq746hh441yh2TiQ4A6505h32ri33Er1wAs7371QQsTA58DTy4f2Q2ppw.jpg")
);
qcPhotoSet1.QcPhotos.Add(
ModelFactory.CreateQcPhoto(qcPhotoSet1,
"https://gooles.oss-cn-hongkong.aliyuncs.com/a20dy0qedii778idq0oeyeh1h5g47ypus61yqre9fy1isa1h96whE6Q26G2542fG2OyETsUrfswUsp0OQ45UG8EQQ4EhyyhhE5Tf.jpg")
);

qcPhotoSet2.QcPhotos.Add(
ModelFactory.CreateQcPhoto(qcPhotoSet2,
"https://gooles.oss-cn-hongkong.aliyuncs.com/74ogtrt934o2w3te9g8gsfwta2q98uui7sdu9fydfi4a21216p4UE4Ef741p0A825pOA095rfsG9wQyO0A2h8hif0DQE97rOE119.jpg")
);

qcPhotoSet2.QcPhotos.Add(
ModelFactory.CreateQcPhoto(qcPhotoSet2,
"https://gooles.oss-cn-hongkong.aliyuncs.com/21tr902otw8sph2i0wh599tews07it5huhosduifpq0g6www3f7Tw9UfUG74rphD504G5QhrU654Ty9GED4D2OfrU9w88h9Qsf09.jpg")
);

qcPhotoSet2.QcPhotos.Add(
ModelFactory.CreateQcPhoto(qcPhotoSet2,
"https://gooles.oss-cn-hongkong.aliyuncs.com/egt18rtdr4hqddt4494euy2q37p59pid3ra3f1dirdhugat14u3ffs6y9h7s5yfAA62AwA3Dff9UwfQOE9AsyQAUUAsA79p477U7.jpg")
);

qcPhotoSet2.QcPhotos.Add(
ModelFactory.CreateQcPhoto(qcPhotoSet2,
"https://gooles.oss-cn-hongkong.aliyuncs.com/a20dy0qedii778idq0oeyeh1h5g47ypus61yqre9fy1isa1h96whE6Q26G2542fG2OyETsUrfswUsp0OQ45UG8EQQ4EhyyhhE5Tf.jpg")
);

qcPhotoSet2.QcPhotos.Add(
ModelFactory.CreateQcPhoto(qcPhotoSet2,
"https://gooles.oss-cn-hongkong.aliyuncs.com/69fh36i47rt08ytp9o97u26wgrrroahif8oyfr69hydwq746hh441yh2TiQ4A6505h32ri33Er1wAs7371QQsTA58DTy4f2Q2ppw.jpg")
);

var set = new HashSet<QcPhotoSet> { qcPhotoSet1, qcPhotoSet3, qcPhotoSet4, qcPhotoSet5 };

// Assert
Assert.Contains(qcPhotoSet2, set);
}
}
[Fact]
public void Contains_ShouldReturnTrue_WhenQcPhotoSetsAreEqual()
{
// Arrange
var product = ModelFactory.CreateProduct();

var qcPhotoSet1 = new QcPhotoSet
{
Product = product,
Source = QcPhotoSource.Sugargoo,
};

var qcPhotoSet2 = new QcPhotoSet
{
Product = product,
Source = QcPhotoSource.Sugargoo,
};

var qcPhotoSet3 = ModelFactory.CreateQcPhotoSet(product, 10);
var qcPhotoSet4 = ModelFactory.CreateQcPhotoSet(product, 10);
var qcPhotoSet5 = ModelFactory.CreateQcPhotoSet(product, 10);

qcPhotoSet1.QcPhotos.Add(
ModelFactory.CreateQcPhoto(qcPhotoSet1,
"https://gooles.oss-cn-hongkong.aliyuncs.com/21tr902otw8sph2i0wh599tews07it5huhosduifpq0g6www3f7Tw9UfUG74rphD504G5QhrU654Ty9GED4D2OfrU9w88h9Qsf09.jpg")
);
qcPhotoSet1.QcPhotos.Add(
ModelFactory.CreateQcPhoto(qcPhotoSet1,
"https://gooles.oss-cn-hongkong.aliyuncs.com/74ogtrt934o2w3te9g8gsfwta2q98uui7sdu9fydfi4a21216p4UE4Ef741p0A825pOA095rfsG9wQyO0A2h8hif0DQE97rOE119.jpg")
);
qcPhotoSet1.QcPhotos.Add(
ModelFactory.CreateQcPhoto(qcPhotoSet1,
"https://gooles.oss-cn-hongkong.aliyuncs.com/egt18rtdr4hqddt4494euy2q37p59pid3ra3f1dirdhugat14u3ffs6y9h7s5yfAA62AwA3Dff9UwfQOE9AsyQAUUAsA79p477U7.jpg")
);
qcPhotoSet1.QcPhotos.Add(
ModelFactory.CreateQcPhoto(qcPhotoSet1,
"https://gooles.oss-cn-hongkong.aliyuncs.com/69fh36i47rt08ytp9o97u26wgrrroahif8oyfr69hydwq746hh441yh2TiQ4A6505h32ri33Er1wAs7371QQsTA58DTy4f2Q2ppw.jpg")
);
qcPhotoSet1.QcPhotos.Add(
ModelFactory.CreateQcPhoto(qcPhotoSet1,
"https://gooles.oss-cn-hongkong.aliyuncs.com/a20dy0qedii778idq0oeyeh1h5g47ypus61yqre9fy1isa1h96whE6Q26G2542fG2OyETsUrfswUsp0OQ45UG8EQQ4EhyyhhE5Tf.jpg")
);

qcPhotoSet2.QcPhotos.Add(
ModelFactory.CreateQcPhoto(qcPhotoSet2,
"https://gooles.oss-cn-hongkong.aliyuncs.com/74ogtrt934o2w3te9g8gsfwta2q98uui7sdu9fydfi4a21216p4UE4Ef741p0A825pOA095rfsG9wQyO0A2h8hif0DQE97rOE119.jpg")
);

qcPhotoSet2.QcPhotos.Add(
ModelFactory.CreateQcPhoto(qcPhotoSet2,
"https://gooles.oss-cn-hongkong.aliyuncs.com/21tr902otw8sph2i0wh599tews07it5huhosduifpq0g6www3f7Tw9UfUG74rphD504G5QhrU654Ty9GED4D2OfrU9w88h9Qsf09.jpg")
);

qcPhotoSet2.QcPhotos.Add(
ModelFactory.CreateQcPhoto(qcPhotoSet2,
"https://gooles.oss-cn-hongkong.aliyuncs.com/egt18rtdr4hqddt4494euy2q37p59pid3ra3f1dirdhugat14u3ffs6y9h7s5yfAA62AwA3Dff9UwfQOE9AsyQAUUAsA79p477U7.jpg")
);

qcPhotoSet2.QcPhotos.Add(
ModelFactory.CreateQcPhoto(qcPhotoSet2,
"https://gooles.oss-cn-hongkong.aliyuncs.com/a20dy0qedii778idq0oeyeh1h5g47ypus61yqre9fy1isa1h96whE6Q26G2542fG2OyETsUrfswUsp0OQ45UG8EQQ4EhyyhhE5Tf.jpg")
);

qcPhotoSet2.QcPhotos.Add(
ModelFactory.CreateQcPhoto(qcPhotoSet2,
"https://gooles.oss-cn-hongkong.aliyuncs.com/69fh36i47rt08ytp9o97u26wgrrroahif8oyfr69hydwq746hh441yh2TiQ4A6505h32ri33Er1wAs7371QQsTA58DTy4f2Q2ppw.jpg")
);

var set = new HashSet<QcPhotoSet> { qcPhotoSet1, qcPhotoSet3, qcPhotoSet4, qcPhotoSet5 };

// Assert
Assert.Contains(qcPhotoSet2, set);
}
}
this unit test also passes fine so I genuinely have no idea what is going on here
Pobiega
Pobiega•this hour
interesting oooh I know why your hashcode depends on non-readonly values thats a nogo
eli
eliOP•this hour
but the hashcodes are the same when I log it
Pobiega
Pobiega•this hour
I chagned your hashcode method
public override int GetHashCode()
{
return Source.GetHashCode();
}
public override int GetHashCode()
{
return Source.GetHashCode();
}
and it works assuming source is a string it wasnt specified, so I guessed :p this works with and without equatable
eli
eliOP•this hour
my current code works fine in my unit test Source is an enum
Anton
Anton•this hour
it's cached for classes, no?
eli
eliOP•this hour
foreach (var qcPhotoSetDetail in aggregatedDetails.QcPhotoSetDetails)
{
var qcPhotoSet = new QcPhotoSet // We need to create a new QcPhotoSet because we can't compare them directly
{
Product = product, // Setting this does not add it to the product unless we save it
Attributes = qcPhotoSetDetail.Attributes,
Source = qcPhotoSetDetail.Source,
};

_logger.LogInformation("New QcPhotoSet: {QcPhotoSet}", qcPhotoSet);

foreach (var url in qcPhotoSetDetail.Urls)
{
qcPhotoSet.QcPhotos.Add(new QcPhoto { OriginalPhotoUrl = url, QcPhotoSet = qcPhotoSet });
}

_logger.LogInformation("Number of existing QC Photos is {Count}", product.QcPhotoSets.Count);

// Log the type of the products set
_logger.LogInformation("Type of product.QcPhotoSets: {Type}", product.QcPhotoSets.GetType());

if (!product.QcPhotoSets.Contains(qcPhotoSet))
{
var existingQcPhotoSet = product.QcPhotoSets.FirstOrDefault(q => q.Equals(qcPhotoSet));

if (existingQcPhotoSet != null)
{
_logger.LogInformation("Existing QcPhotoSet {QcPhotoSet} already exists", existingQcPhotoSet);
_logger.LogInformation("Existing hashcode {ExistingHashCode} New hashcode {NewHashCode}, {Equal}", existingQcPhotoSet.GetHashCode(), qcPhotoSet.GetHashCode(), existingQcPhotoSet.Equals(qcPhotoSet));

}

_logger.LogInformation("Adding new QcPhotoSet {QcPhotoSet}", qcPhotoSet);
product.QcPhotoSets.Add(qcPhotoSet); // If it doesn't exist, add it
hasChanged = true;
}
}
foreach (var qcPhotoSetDetail in aggregatedDetails.QcPhotoSetDetails)
{
var qcPhotoSet = new QcPhotoSet // We need to create a new QcPhotoSet because we can't compare them directly
{
Product = product, // Setting this does not add it to the product unless we save it
Attributes = qcPhotoSetDetail.Attributes,
Source = qcPhotoSetDetail.Source,
};

_logger.LogInformation("New QcPhotoSet: {QcPhotoSet}", qcPhotoSet);

foreach (var url in qcPhotoSetDetail.Urls)
{
qcPhotoSet.QcPhotos.Add(new QcPhoto { OriginalPhotoUrl = url, QcPhotoSet = qcPhotoSet });
}

_logger.LogInformation("Number of existing QC Photos is {Count}", product.QcPhotoSets.Count);

// Log the type of the products set
_logger.LogInformation("Type of product.QcPhotoSets: {Type}", product.QcPhotoSets.GetType());

if (!product.QcPhotoSets.Contains(qcPhotoSet))
{
var existingQcPhotoSet = product.QcPhotoSets.FirstOrDefault(q => q.Equals(qcPhotoSet));

if (existingQcPhotoSet != null)
{
_logger.LogInformation("Existing QcPhotoSet {QcPhotoSet} already exists", existingQcPhotoSet);
_logger.LogInformation("Existing hashcode {ExistingHashCode} New hashcode {NewHashCode}, {Equal}", existingQcPhotoSet.GetHashCode(), qcPhotoSet.GetHashCode(), existingQcPhotoSet.Equals(qcPhotoSet));

}

_logger.LogInformation("Adding new QcPhotoSet {QcPhotoSet}", qcPhotoSet);
product.QcPhotoSets.Add(qcPhotoSet); // If it doesn't exist, add it
hasChanged = true;
}
}
Anton
Anton•this hour
actually it can't be if it's called directly
eli
eliOP•this hour
logger.LogInformation("Existing hashcode {ExistingHashCode} New hashcode {NewHashCode}, {Equal}", existingQcPhotoSet.GetHashCode(), qcPhotoSet.GetHashCode(), existingQcPhotoSet.Equals(qcPhotoSet)); This log only fires if contains returned False Existing hashcode 1581568506 New hashcode 1581568506, True hashcodes are the same and equals returned true inside the "not contains block" and no data changed so the hashcode should be the same when I call the if statement as well 🤷 I don't think non readonly is the issue?
Pobiega
Pobiega•this hour
well, here is my test sample
var b = new QcPhotoSet
{
Source = "xxx",
QcPhotos = new HashSet<QcPhoto>
{
new()
{
OriginalPhotoUrl =
new Uri("http://google.cmo/asd.png")
},
}
};
var b = new QcPhotoSet
{
Source = "xxx",
QcPhotos = new HashSet<QcPhoto>
{
new()
{
OriginalPhotoUrl =
new Uri("http://google.cmo/asd.png")
},
}
};
I have two of these, called a and b both set up "from scratch" so to speak a set with just a in it did NOT contain b at first but after I changed QcPhotoSets hashcode, it did hm
public override int GetHashCode()
{
var subhash = QcPhotos.Aggregate(0, (current, photo) => current ^ photo.GetHashCode());

return HashCode.Combine(Source, subhash);
}
public override int GetHashCode()
{
var subhash = QcPhotos.Aggregate(0, (current, photo) => current ^ photo.GetHashCode());

return HashCode.Combine(Source, subhash);
}
seems to work too actually now im really confused. its saying yes to the original code now too but it didnt at first :d
eli
eliOP•this hour
[Fact]
public void PobiegaTest()
{
var product = ModelFactory.CreateProduct();

var a = new QcPhotoSet()
{
Product = product,
Source = QcPhotoSource.Sugargoo
};

var a_photo = new QcPhoto()
{
OriginalPhotoUrl = new Uri("https://test.com/1.png"),
QcPhotoSet = a
};

a.QcPhotos.Add(a_photo);

var b = new QcPhotoSet()
{
Product = product,
Source = QcPhotoSource.Sugargoo
};

var b_photo = new QcPhoto()
{
OriginalPhotoUrl = new Uri("https://test.com/1.png"),
QcPhotoSet = b
};

b.QcPhotos.Add(b_photo);

var set = new HashSet<QcPhotoSet>();

set.Add(a);

Assert.Contains(b, set);
}
[Fact]
public void PobiegaTest()
{
var product = ModelFactory.CreateProduct();

var a = new QcPhotoSet()
{
Product = product,
Source = QcPhotoSource.Sugargoo
};

var a_photo = new QcPhoto()
{
OriginalPhotoUrl = new Uri("https://test.com/1.png"),
QcPhotoSet = a
};

a.QcPhotos.Add(a_photo);

var b = new QcPhotoSet()
{
Product = product,
Source = QcPhotoSource.Sugargoo
};

var b_photo = new QcPhoto()
{
OriginalPhotoUrl = new Uri("https://test.com/1.png"),
QcPhotoSet = b
};

b.QcPhotos.Add(b_photo);

var set = new HashSet<QcPhotoSet>();

set.Add(a);

Assert.Contains(b, set);
}
My existing code passes this test which I believe is the same as what you're doing?
Pobiega
Pobiega•this hour
pretty much, yes
eli
eliOP•this hour
I might just give up and use a .Any(q => q.Equals(qcPhotoSet)) lol I genuinely have no idea what is causing this
Pobiega
Pobiega•this hour
hm well are you mutating your QcPhotoSets at all after inserting them into any Set? because that would be a problem but it wouldnt be the cause of this problem, I think
eli
eliOP•this hour
So wait when I call Contains does it compute the hashcode then and there or is it cached? I woudln't be suprised if that cuased issues when using EF
Pobiega
Pobiega•this hour
Id assume it calculates for b, but compares it to all known a which ARE cached since the internals for a HashSet uses the hashcode to index an array its a bit tricky using equals on collections, which is why SetEqual etc exists
eli
eliOP•23h ago
public override int GetHashCode()
{
return 1;
}
public override int GetHashCode()
{
return 1;
}
sanity check time lets see if it works if it's just basing on equals @Pobiega omg that worked :notecrine: Alright lesson learned you were right Now to figure out what I should base my hashcodes of off since evverything is properties lol ty for the help guys Ah I understand the issue now EF Gets a product EF then gets the Qc Photo Sets (but not the Qc Photos within them) and adds them to the products set based off the computed hash currently Then EF adds the Qc Photos within the Qc Photo sets and the hashcode is changed but their slot in hashset is based off old hashcode Just gonna change my implementation to use a List and remember to always check Contains because there isn't really anything meaningful I can generate the hashcode from that won't cause this issue
Want results from more Discord servers?
Add your server