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

CheckList fails on unidirectional one-to-many relationships #212

Closed
brantb opened this issue Mar 14, 2013 · 7 comments · Fixed by #688
Closed

CheckList fails on unidirectional one-to-many relationships #212

brantb opened this issue Mar 14, 2013 · 7 comments · Fixed by #688
Assignees

Comments

@brantb
Copy link

brantb commented Mar 14, 2013

Given the following domain model and mappings:

public class Order {
    public virtual Guid Id { get; set; }
    public virtual ICollection<LineItem> LineItems { get; set; }
}
public class LineItem {
    public virtual Guid Id { get; set; }
}
// OrderMap.cs
Id(x => x.Id).GeneratedBy.GuidComb();
HasMany(x => x.LineItems)
  .Not.Inverse()
  .Not.KeyNullable()
  .Not.KeyUpdate()
  .Cascade.AllDeleteOrphan();
// LineItemMap.cs
Id(x => x.Id).GeneratedBy.GuidComb();

The following code will throw a PropertyValueException when CheckList() is called:

var order = new Order() { LineItems = new List<LineItem>() };
order.LineItems.Add(new LineItem());
new PersistenceSpecification<Order>(session)
  /* NHibernate.PropertyValueException: not-null property references 
   * a null or transient value LineItem._Order.LineItemsBackref */
    .CheckList(o => o.LineItems, order.LineItems)
    .VerifyTheMappings();

This happens because CheckList() tries to immediately save the LineItems in the list, which doesn't work because the relationship is unidirectional.

@chester89
Copy link
Collaborator

ok, I understand the issue - now the question is what do we do about it?

@ghost ghost assigned chester89 Mar 24, 2013
@brantb
Copy link
Author

brantb commented Mar 28, 2013

Unfortunately, I don't have any ideas.

My tests were failing and I spent some time figuring out why. I reported the issue in hopes of saving other people's time doing the same. I don't necessarily expect a fix, although I suppose the documentation could be updated to mention that this isn't a supported scenario.

@chester89
Copy link
Collaborator

about documentation - I couldn't agree more.

@dhilgarth
Copy link

What about giving ReferenceList (and ReferenceProperty) an indicator whether or not it is should be saved with / by the parent? Something like this:

public class ReferenceList<T, TListElement> : List<T, TListElement>
{
    private readonly bool _isInverse;

    public ReferenceList(Accessor property, IEnumerable<TListElement> value)
        : this(property, value, true)
    { }

    public ReferenceList(Accessor property, IEnumerable<TListElement> value, bool isInverse)
        : base(property, value)
    {
        _isInverse = isInverse;
    }

    public override void HasRegistered(PersistenceSpecification<T> specification)
    {
        if(!_isInverse)
            return;

        foreach (TListElement item in Expected)
        {
            specification.TransactionalSave(item);
        }
    }
}

In addition to changing the classes, it would be necessary to update the extension methods to actually allow supplying this parameter.

@dhilgarth
Copy link

A short test for my specific scenario shows that this would work.

@chester89
Copy link
Collaborator

chester89 commented Jun 5, 2013

That's great news.
I'll try to apply your changes to the codebase - if all goes well, that'll
be in the next release.
Thanks.

@hazzik
Copy link
Member

hazzik commented May 8, 2024

CheckInverseList should be used.

hazzik added a commit that referenced this issue May 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants