English 中文(简体)
NHibernate EventListeners - getting the value of a property of the entity being saved
原标题:

I m implementing a custom EventListener to save auditing information in NHibernate.

I m currently extending DefaultSaveOrUpdateEventListener, overriding PerformSaveOrUpdate, going through the properties of each entity and saving them elsewhere.

This works with simple properties, but fails when cascade-saving a one-to-many relationship.

If I take the following entities:

[ActiveRecord]
public class Child
{
    [PrimaryKey(PrimaryKeyType.GuidComb)]
    public Guid Id { get; set; }

    [BelongsTo]
    public Parent Parent { get; set; }
}

[ActiveRecord]
public class Parent
{
    [PrimaryKey(PrimaryKeyType.GuidComb)]
    public Guid Id { get; set; }

    [HasMany(Cascade = ManyRelationCascadeEnum.SaveUpdate)]
    public IList<Child> Children { get; set; }
}

And then save a parent with a child:

ActiveRecordMediator<Parent>.Save(new Parent
{
    Children = new List<Child>
    {
        new Child()
    }
});

The child will get the correct parent assigned to it when its persisted to the database but the Parent property of the child is null when my EventListener is called.

How can I get the value that will actually be persisted to the database in this case?

[EDIT] I ve recently been looking at getting this to work by hooking the cascade and seeing what else was being saved at the time, but that seems horribly unreliable and I d much prefer to get the data out of NHibernate so I know it s consistent with the database.

最佳回答

I m not sure how you can accomplish this with ActiveRecord but it has to do with the mechanism in which NHibernate persists parent/child relationships.

Saving the child cascade prior to saving the parent in NHibernate is by design depending on which end of the relationship is marked as "inverse=true" and the child needs to have a "not-null=true" attribute on the element (which determines which end owns the relationship). This will make it so the Child is managing the state of the relationship.

Then you can simply save the child, and the parent will be updated with the appropriate information. This will generate one INSERT statement, instead of an INSERT AND UPDATE that you are probably seeing now. Not sure if this solves your problem, but I believe the problem you are having is around this behavior. You can read more at this link:

https://www.hibernate.org/hib_docs/nhibernate/html/example-parentchild.html

问题回答

I see that you use Castle ActiveRecord. I was experimenting with it also.

There is some weirdness in it, because in the code you provided, the Child object s Parent property will only be set after your stuff is saved to the database. Until then, its value will be null. (I don t know if this behaviour is specific to ActiveRecord, or also NHibernate.)

Perhaps if you assign the Parent properties of the Child objects by hand, it will work.

var parent = new Parent();
var child = new Child()
{
    Parent = parent
};
parent.Children.Add(child);

ActiveRecordMediator<Parent>.Save(child);
ActiveRecordMediator<Parent>.Save(parent);

Maybe the order in which you save the entities also has to do something with this matter.

I don t use ActiveRecord, I use NHibernate instead so I m going to assume that they handle parent-child relationships in the same way (https://www.hibernate.org/hib_docs/nhibernate/html/example-parentchild.html)

What happens if you leave the ORM to manage the link to the parent (by setting Inverse=true in the HasMany attribute)?

[ActiveRecord]
public class Parent
{
    [PrimaryKey(PrimaryKeyType.GuidComb)]
    public Guid Id { get; set; }

    [HasMany(Cascade = ManyRelationCascadeEnum.SaveUpdate, Inverse=true)]
    public IList<Child> Children { get; set; }
}




相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签