Skip to content
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

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);

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

No branches or pull requests

2 participants