Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Equals is ignored for Components that contain collection #3539

Open
DmitryMak opened this issue May 2, 2024 · 5 comments
Open

Equals is ignored for Components that contain collection #3539

DmitryMak opened this issue May 2, 2024 · 5 comments

Comments

@DmitryMak
Copy link

DmitryMak commented May 2, 2024

NHibernate ignores Equals implementation on Components when they contain a collection. As a result, it issues an unnecessary DELETE followed by multiple INSERTs. It basically recreates all rows that were backing the collection even though the collection has not changed.

Example:


<class name="Person">
    <component name="CreditInfo">
        <bag name="OldCards" cascade="all" >
            <key column="PersonId" />
                ...


class Person {
    public CreditInfo CreditInfo;
}

public class CreditInfo {
    public readonly ICollection<String> OldCards;

    public CreditInfo(IEnumerable<String> oldCards) {        
        OldCards = new List<String>(oldCards);
    }
    
    public override Boolean Equals(Object obj) {

        var other = (CreditInfo)obj;
        return OldCards.SequenceEqual(other.OldCards);  <-- No changes detected by Equals!
    }
}

 
person.CreditInfo = new CreditInfo(person.CreditInfo.OldCards);  <-- effectively cloned

// will DELETE all card rows and INSERT all of them again even though CreditInfo did not change

I think there are 2 counterintuitive behaviors here:

  1. Why is NHibernate ignoring CreditInfo.Equals? The method tells it that the component (value type) has not changed. A very common immutable Value Object scenario. Why does it have to go 'inside' the component?

  2. Replacing NHibernate collection (backing OldCards) with a new collection with the same items seem to make NHibernate delete and reinsert all rows. Is there a way to implement value equality on collections, think SequenceEquals?

@DmitryMak
Copy link
Author

Essentially I want to implement a small immutable collection that is compared by value (SequenceEquals). It looks like my only option is to serialize the collection into a string and store it as a column.

@hazzik
Copy link
Member

hazzik commented May 2, 2024

@DmitryMak can you submit a test case?

@DmitryMak
Copy link
Author

DmitryMak commented May 3, 2024

@hazzik I submitted a PR with a test that explains what I meant. Though I'm not sure how to write an assertion that fails when an unexpected DML is issued.

@hazzik
Copy link
Member

hazzik commented May 3, 2024

You have incorrect GetHashCode generation. It assumes hash code of an instance of a set, instead of it's elements.

@hazzik
Copy link
Member

hazzik commented May 3, 2024

I'm not sure how to write an assertion that fails when an unexpected DML is issued.

Something like this:

using var spy = new SqlLogSpy();
t.Commit();
Assert.That(spy.GetWholeLog(), Is.Empty);

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants