NHibernate 3.2通过代码映射会忽略我的IUserType - c#

我有一个LocalizedString分类用于存储单个值的本地化。该概念大致基于post by Fabio Maulo。

我正在NHibernate 3.2中使用新的Mapping-By-Code概念,但是它似乎忽略了IUserType实现,因为在生成SQL时,它将创建一个具有不同名称和默认字符串NVARCHAR(255)的列类型。

我正在尝试映射这个简单的课程

public class Region : Entity
{
    /// <summary>
    /// Initializes a new instance of the <see cref="Region"/> class.
    /// </summary>
    public Region()
    {
    }

    /// <summary>
    /// Gets or sets the localized name of the <see cref="Region"/>.
    /// </summary>
    public virtual LocalizedString Name { get; set; }
}

结果SQL是

create table Regions (RegionId INT not null, Item NVARCHAR(255) not null, primary key (RegionId))

此处的Item列应称为Name,并且应为XML类型。我认为列名称来自LocalizedString的索引器名称。

这是我的NHibernate配置(尚未完成,我正在构建约定)

private static Configuration CreateNHibernateConfiguration()
{
    var cfg = new Configuration();
    cfg.Proxy(p => p.ProxyFactoryFactory<NHibernate.Bytecode.DefaultProxyFactoryFactory>())
        .DataBaseIntegration(db =>
        {
            db.ConnectionStringName = "***";
            db.Dialect<MsSql2008Dialect>();
            db.BatchSize = 500;
        });

    var mapper = new ConventionModelMapper();
    var baseEntityType = typeof(Entity);
    mapper.IsEntity((t, declared) => baseEntityType.IsAssignableFrom(t) && baseEntityType != t && !t.IsInterface);
    mapper.IsRootEntity((t, declared) => baseEntityType.Equals(t.BaseType));

    mapper.BeforeMapClass += (mi, t, map) =>
            {
                map.Table(Inflector.MakePlural(t.Name));
                map.Id(x =>
                    {
                        x.Column(t.Name + "Id");
                    });
            };

    mapper.BeforeMapManyToOne += (insp, prop, map) =>
            {
                map.Column(prop.LocalMember.GetPropertyOrFieldType().Name + "Id");
                map.Cascade(Cascade.Persist);
            };

    mapper.BeforeMapBag += (insp, prop, map) =>
            {
                map.Key(km => km.Column(prop.GetContainerEntity(insp).Name + "Id"));
                map.Cascade(Cascade.All);
            };

    mapper.BeforeMapProperty += (insp, prop, map) =>
            {
                map.NotNullable(true);
            };

    var exportedTypes = baseEntityType.Assembly.GetExportedTypes();
    mapper.AddMappings(exportedTypes.Where(t => t.Namespace.EndsWith("Mappings", StringComparison.Ordinal)));

    var mapping = mapper.CompileMappingFor(exportedTypes.Where(t => t.Namespace.EndsWith("Data", StringComparison.Ordinal)));

    cfg.AddDeserializedMapping(mapping, "MyModel");
    SchemaMetadataUpdater.QuoteTableAndColumns(cfg);

    return cfg;
}

这是我的IUserType类的LocalizedString定义:

/// <summary>
/// Defines a string that can have a different value in multiple cultures.
/// </summary>
public sealed partial class LocalizedString : IUserType
{
    object IUserType.Assemble(object cached, object owner)
    {
        var value = cached as string;
        if (value != null)
        {
            return LocalizedString.Parse(value);
        }

        return null;
    }

    object IUserType.DeepCopy(object value)
    {
        var toCopy = value as LocalizedString;
        if (toCopy == null)
        {
            return null;
        }

        var localizedString = new LocalizedString();
        foreach (var localizedValue in toCopy.localizedValues)
        {
            localizedString.localizedValues.Add(localizedValue.Key, localizedValue.Value);
        }

        return localizedString;
    }

    object IUserType.Disassemble(object value)
    {
        var localizedString = value as LocalizedString;
        if (localizedString != null)
        {
            return localizedString.ToXml();
        }

        return null;
    }

    bool IUserType.Equals(object x, object y)
    {
        if (x == null && y == null)
        {
            return true;
        }

        if (x == null || y == null)
        {
            return false;
        }

        var localizedStringX = (LocalizedString)x;
        var localizedStringY = (LocalizedString)y;

        if (localizedStringX.localizedValues.Count() != localizedStringY.localizedValues.Count())
        {
            return false;
        }

        foreach (var value in localizedStringX.localizedValues)
        {
            if (!localizedStringY.localizedValues.ContainsKey(value.Key) || localizedStringY.localizedValues[value.Key] == value.Value)
            {
                return false;
            }
        }

        return true;
    }

    int IUserType.GetHashCode(object x)
    {
        if (x == null)
        {
            throw new ArgumentNullException("x");
        }

        return x.GetHashCode();
    }

    bool IUserType.IsMutable
    {
        get { return true; }
    }

    object IUserType.NullSafeGet(System.Data.IDataReader rs, string[] names, object owner)
    {
        if (rs == null)
        {
            throw new ArgumentNullException("rs");
        }

        if (names == null)
        {
            throw new ArgumentNullException("names");
        }

        if (names.Length != 1)
        {
            throw new InvalidOperationException("names array has more than one element. can't handle this!");
        }

        var val = rs[names[0]] as string;

        if (val != null)
        {
            return LocalizedString.Parse(val);
        }

        return null;
    }

    void IUserType.NullSafeSet(System.Data.IDbCommand cmd, object value, int index)
    {
        if (cmd == null)
        {
            throw new ArgumentNullException("cmd");
        }

        var parameter = (DbParameter)cmd.Parameters[index];

        var localizedString = value as LocalizedString;
        if (localizedString == null)
        {
            parameter.Value = DBNull.Value;
        }
        else
        {
            parameter.Value = localizedString.ToXml();
        }
    }

    object IUserType.Replace(object original, object target, object owner)
    {
        throw new NotImplementedException();
    }

    Type IUserType.ReturnedType
    {
        get { return typeof(LocalizedString); }
    }

    NHibernate.SqlTypes.SqlType[] IUserType.SqlTypes
    {
        get { return new[] { new XmlSqlType() }; }
    }
}

参考方案

您不应在域模型中使用IUserType。

实际上,应该将IUserType接口称为类似IUserTypeMapper的接口,并且必须在映射中显式指定它。

我建议您重新阅读该帖子。

更新:尝试按常规映射您的类型:

mapper.BeforeMapProperty +=
    (insp, prop, map) =>
    {
        if (/*determine if this is member should be mapped as LocalizedString*/)
            map.Type<LocalizedString>();
    };

当然,“确定是否...”部分将由您确定,例如以“ Localized”开头的属性名称,自定义属性或您想要的任何东西。

使用数组填充动态下拉列表 - php

我正在尝试使用多维数组在PHP中进行动态下拉列表。我的第一个选择框正确填充,但是在选择建筑物时,我需要第二个选择框来显示用于第一个选择的相应显示(大厅,休息室等)这是数组:$displays = array( "Company" => array( "Building 1"=>array( "Di…

使用javascript在客户端的列表视图中选择所有复选框 - javascript

我有一个列表视图,在标题中有一个复选框。如果标题复选框已选中/未选中,我想选择行中的所有复选框。如何在客户端实现此目标?这是ListView设计代码。<asp:ListView ID="lvTypes" runat="server" GroupPlaceholderID="groupPlaceHolde…

将值设置为无法与jQuery一起使用的隐藏字段 - javascript

我有一个使用Visual Studio 2013创建的应用程序,但是在使用jQuery向隐藏字段分配值时遇到了一些问题。首先,我要为隐藏变量分配一个值,因为我无法直接访问.cs文件中标签的文本值,因此我必须将标签的值分配给隐藏的输入字段才能访问在.cs文件中。我希望这是有道理的。这是我在.aspx文件中的隐藏输入字段: <input type=…

Div单击与单选按钮相同吗? - php

有没有一种方法可以使div上的click事件与表单环境中的单选按钮相同?我只希望下面的div提交值,单选按钮很丑代码输出如下:<input id="radio-2011-06-08" value="2011-06-08" type="radio" name="radio_date&#…

Ajax表单未获得结果 - javascript

我有一个带有搜索功能的主页。从主页搜索可以正常工作,但是当我尝试使用ajax表单(在url.com/search?id=biology上)再次搜索时,我被重定向到404页面,提示未找到/Search。主页上的表格:@using (Html.BeginForm("Index", "Search", new { Retur…