Fluent NHibernate enforce Not Nullable on Foreign

2019-02-10 07:54发布

Just getting my feet wet with some Fluent NHibernate AutoMap conventions, and ran into something I couldn't figure out. I assume I'm just not looking in the right place... Basically trying to enforce NOT-NULL on the "many" side of the one to many relationship. It seems, using the automapping, it always makes the parent property Id nullable in the database.

I did some searching on StackOverFlow and found similar questions, but nothing relating to AutoMapping and Conventions though (unless I missed it).

Quick example...

public class Group    // One Group
{
    public Group() { this.Jobs = new List<Job>(); }
    public virtual Guid Id { get; set; }
    public virtual string Name { get; set; }
    public virtual IList<Job> Jobs { get; protected set; }
}

public class Job    // Has many Jobs
{
    public virtual Guid Id { get; set; }
    public virtual string Name { get; set; }

    // Trying to make this field not-nullable in the database.
    public virtual Group Group { get; set; }
}

I thought I'd be able to just create a convention like...

public class OneToManyConvention : IHasOneConvention
{
    public void Apply(IOneToOneInstance instance)
    {
        // Nullable() isn't a valid method...
        instance.Not.Nullable();   
    }
}

But it seems IOneToOnInstance doesn't have a Nullable() method. I can do this if I create a Map file for Job, but trying to avoid any Map files and stick with auto-mapping.

I came across this link on the Fluent group list describing something similar.

Which describes something like this...

public class NotNullPropertyConvention : IPropertyConvention
{
    public bool Accept(IProperty target)
    {
            return true;
    }
    public void Apply(IProperty target)
    {
            target.Not.Nullable();
    }
}

But that raises the questions of... 1) How would I determine IProperty to be a Job (or any child property that is a link back to the parent)

2) It made a mention on that page that using this would override my manual overrides, eg. if a very specific property link needed to be NULL. Which would be an issue (if it's still an issue, but can't test without figuring out #1 first)

Any ideas on this? Am I just missing something?



Update 1

Still no go. Even the following still doesn't enforce Not-Nullable in the database schema...

public class FluentConvention : IPropertyConvention
{
    public void Apply(IPropertyInstance instance)
    {
        instance.Not.Nullable();
    }
}

It does for all of the other fields though...
/shrug

Any ideas?



Update 2

While this isn't the answer I was looking for, I did find a work around... I was using NHibernate Validator assembly, and within that assembly there is a [NotNull] attribute. If I decorated my class with the Validator attribute, and associated the ValidationEngine to NHibernate before the schema creation, it would tag the FK database column as Not-Nullable.

public class Job    // Has many Jobs
{
    public virtual Guid Id { get; set; }
    public virtual string Name { get; set; }

    [NHibernate.Validator.Constraints.NotNull]
    public virtual Group Group { get; set; }
}

If anyone needs the full code for the NHibernate + ValidationEngine initialization, just let me know. Still looking for a way to do it using the pure mapping convention route though if anyone has any info...

Thanks!

2条回答
等我变得足够好
2楼-- · 2019-02-10 08:39

You can override the auto-mapped properties as part of your AutoMap in Fluenttly.Configure().

So you can do this:

.Override<Job>(map => map.References(x => x.Group).Not.Nullable())

It's not exactly convenient if you have a lot of classes that need this though.

Edit: You can also specify the override in a class that implements IAutoMappingOverride like so:

    public class JobMappingOverride : IAutoMappingOverride<Job>
    {
            public void Override(AutoMapping<Job> mapping)
            {
                    mapping.References(x => x.Group).Not.Nullable();
            }
    }

and include it like so:

    .UseOverridesFromAssemblyOf<JobMappingOverride>()

This would keep your fluent configuration a little cleaner.

查看更多
成全新的幸福
3楼-- · 2019-02-10 08:48

It seems that IPropertyConvention is only called on simple properties of your classes. If your property references another class, you need to use IReferenceConvention too.

Try this:

public class FluentConvention : IPropertyConvention, IReferenceConvention  
{      
    public void Apply(IPropertyInstance instance)
    {          
        instance.Not.Nullable();      
    }

    public void Apply(IManyToOneInstance instance)
    {
        instance.Not.Nullable();
    }
}      
查看更多
登录 后发表回答