NHibernate动态组件默认值问题

时间:2014-10-23 11:18:51

标签: nhibernate nhibernate-mapping

我的所有实体(映射到数据库表)都从一个实体类继承,其上有一个名为Attributes的动态组件,例如:

public abstract class Entity<T> {
    public virtual T Id { get; set; }

    private IDictionary _attributes;

    public virtual IDictionary Attributes {
        get { return _attributes ?? (_attributes = new Hashtable()); }
        set { _attributes = value; }
    }
}

Attributes集合允许我为每个实体添加额外的字段,而无需直接更改实体本身。这使我可以使我的应用程序更加模块化。

例如说我有以下实体:

public class User : Entity<int> {
    public virtual string Name { get; set; }
}

现在说我有一个论坛模块,需要针对用户的NumPosts属性。我会在数据库中的Users表中添加该字段。此字段不可为空,默认值为0.然后,使用动态组件对用户实体映射字段。

但是当我尝试插入用户时说:

session.Save(new User() { Name = "Test" });

它抛出一个错误,因为它期望我为NumPosts设置一个值,生成的SQL将是这样的:

  

INSERT INTO Users(Name,NumPosts)VALUES('Test',NULL)

然而,NumPosts不允许空值,因此也不允许出错。理想情况下,如果Attributes集合不包含NumPosts的条目,我想要说下面的内容:

  

插入用户(名称)VALUES('测试')

另一种方法是说以下哪种方法可以正常工作:

session.Save(new User() { Name = "Test", Attributes = new Hashtable() { { "NumPosts", 0 } } });

我遇到的问题是我不希望模块彼此依赖,我不能说这个。

供参考,这是一个简单的会话工厂方法版本,它映射NumPosts字段:

return Fluently.Configure()
    ...
    .ExposeConfiguration(c => {
        // Get the persistent class
        var persistentClass = c.GetClassMapping("User");

        // Create the attributes component
        var component = new Component(persistentClass);

        // Create a simple value
        var simpleValue = new SimpleValue(persistentClass.Table);

        // Set the type name
        simpleValue.TypeName = "Int32";

        // Create a new db column specification
        var column = new Column("NumPosts");
        column.Value = simpleValue;
        column.Length = 10;
        column.IsNullable = false;
        column.DefaultValue = "0";

        // Add the column to the value
        simpleValue.AddColumn(column);

        // Ad the value to the component
        component.AddProperty(new Property() { Name = column.Name, Value = simpleValue });

        // Add the component property
        persistentClass.AddProperty(new Property() { Name = "Attributes", Value = component });
    })
    .BuildConfiguration();

如果有可能,有人可以告诉我,我很感激。感谢

1 个答案:

答案 0 :(得分:1)

您知道如何使其按上述方式工作:

  

......另一种方法是说以下哪种方法可以正常工作:

session.Save(new User() 
{ 
   Name = "Test", Attributes = new Hashtable() { { "NumPosts", 0 } } 
});
  

...我遇到的问题是我不希望模块彼此依赖,我真的不能这样说......

如果最大的问题是明确的Attributes初始化(“... 我不希望模块具有依赖性 ...”) 我们可以使用:

12.2. Event system

所以,使用像这样的Listener:

[Serializable]
public class MyPersistListener : NHibernate.Event.ISaveOrUpdateEventListener
{
    public void OnSaveOrUpdate(SaveOrUpdateEvent @event)
    {
        var entity = @event.Entity as Entity<int>; // some interface IHaveAttributes
        if (entity == null)                        // would be more appropriate
        {
            return;
        }

        var numPosts = entity.Attributes["NumPosts"] as int?;
        if (numPosts.HasValue)
        {
            return;
        }

        entity.Attributes["NumPosts"] = 0;
    }
}

基于此文档摘要:

Configuration cfg = new Configuration();
ILoadEventListener[] stack = new ILoadEventListener[] { new MyLoadListener(), new DefaultLoadEventListener() };
cfg.EventListeners.LoadEventListeners = stack;

在我们的案例中,这应该是init:

.ExposeConfiguration(c => {
    var stack = new ISaveOrUpdateEventListener [] { new MyPersistListener() };
    c.EventListeners.SaveEventListeners= stack;