1

我已经定义了这个映射:

public class Mapping : ConventionModelMapper
{
    public Mapping()
    {
        IsRootEntity((type, declared) =>
                         {
                             return !type.IsAbstract &&
                                    new[] { typeof(Entity<Guid>), typeof(CommonEntity) }.Contains(type.BaseType);
                         });

        IsEntity((x, y) => typeof(Entity<Guid>).IsAssignableFrom(x) && !x.IsAbstract && !x.IsInterface);

        IsSet((mi, wasDeclared) =>
                  {
                      var propertyType = mi.GetPropertyOrFieldType();
                      return propertyType.IsGenericType && typeof(System.Collections.Generic.ISet<>).IsAssignableFrom(propertyType.GetGenericTypeDefinition());
                  });

        IsManyToMany((mi, wasDeclared) =>
                         {
                             var propertyType = mi.GetPropertyOrFieldType();
                             var containingType = mi.ReflectedType;

                             if (typeof(System.Collections.Generic.ISet<>).IsAssignableFrom(propertyType.GetGenericTypeDefinition()))
                             {
                                 var referenceType = propertyType.GetGenericArguments()[0];
                                 return true;
                                 return !referenceType.GetProperties(BindingFlags.Instance | BindingFlags.Public).Any(p => p.PropertyType.IsAssignableFrom(containingType));
                             }
                             return false;
                         });

        Class<Entity<Guid>>(x =>
                                {
                                    x.Id(c => c.Id, m => m.Generator(Generators.GuidComb));
                                    x.Version(c => c.Version, (vm) => { });
                                });

        BeforeMapClass += OnBeforeMapClass;
        BeforeMapManyToOne += OnBeforeMapManyToOne;
        BeforeMapSet += OnBeforeMapSet;
        BeforeMapManyToMany += OnBeforeMapManyToMany;

        Class<CommonEntity>(x =>
        {
            x.Property(c => c.DateCreated, m => m.Type<UtcDateTimeType>());
            x.Property(c => c.DateModified, m => m.Type<UtcDateTimeType>());
        });
    }

    private void OnBeforeMapManyToMany(IModelInspector modelInspector, PropertyPath member, IManyToManyMapper collectionRelationManyToManyCustomizer)
    {
        collectionRelationManyToManyCustomizer.Column(member.LocalMember.GetPropertyOrFieldType().GetGenericArguments()[0].Name + "Id");
    }

    private void OnBeforeMapSet(IModelInspector modelInspector, PropertyPath member, ISetPropertiesMapper propertyCustomizer)
    {
        propertyCustomizer.Key(k=>k.Column(member.GetContainerEntity(modelInspector).Name + "Id"));
        propertyCustomizer.Cascade(Cascade.Persist);
        if (modelInspector.IsManyToMany(member.LocalMember))
        {
            propertyCustomizer.Table(member.GetContainerEntity(modelInspector).Name +
                                     member.LocalMember.GetPropertyOrFieldType().GetGenericArguments()[0].Name);
        }
    }

    private void OnBeforeMapManyToOne(IModelInspector modelInspector, PropertyPath member, IManyToOneMapper propertyCustomizer)
    {
        propertyCustomizer.Column(member.LocalMember.Name + "Id");
    }

    private void OnBeforeMapClass(IModelInspector modelInspector, Type type, IClassAttributesMapper classCustomizer)
    {
        classCustomizer.Table('['+ type.Name + ']');
    }
}

我遇到了多对多关系的问题。我有用户、用户权限和权限。当我在附加权限后保存用户时,它会生成以下 SQL:

exec sp_executesql N'UPDATE [Permission] SET UserId = @p0 WHERE Id = @p1',N'@p0 uniqueidentifier,@p1 uniqueidentifier',@p0='57A2CD87-4A79-4131-B9CE-A1060168D520',@p1='9D99D340-1B63-4291-B55A-6127A8F34FC9'

当它应该是这样的:

exec sp_executesql N'INSERT INTO UserPermission (UserId, PermissionId) VALUES (@p0, @p1)',N'@p0 uniqueidentifier,@p1 uniqueidentifier',@p0='2C670A01-C2E6-46A3-A412-A1060168F976',@p1='9D99D340-1B63-4291-B55A-6127A8F34FC9'

当我为用户添加特定的类映射时:

        Class<User>(classMapper =>
                        {
                            classMapper.Set(x => x.Permissions, map =>
                                                        {
                                                            //map.Key(k => k.Column("UserId"));
                                                            //map.Table("UserPermission");
                                                        }, r => r.ManyToMany(m => {}));
                        });

我可以省略键和表定义,并在没有列调用的情况下包含 ManyToMany,它可以工作。但它与我的 BeforeManyToMany 事件处理程序做同样的事情。如果我放弃整个 Class 事件,则不会触发 BeforeMapManyToMany 事件,并且 nHibernate 认为我的 Permission 表上有一个 UserId。

继承人用户:

public class User : CommonEntity
{
    protected User()
    {
        Permissions = new HashSet<Permission>();
    }

    public User(User createdBy) : base(createdBy)
    {
        Permissions = new HashSet<Permission>();
    }

    public ISet<Permission> Permissions { get; protected set; }
}
4

1 回答 1

2

在查看源代码后,我意识到问题是在 IsManyToMany 之前定义集合时,对属性进行了 IsOneToMany 检查。我只需要定义 IsOneToMany,它就可以在没有任何显式映射的情况下工作。

        IsOneToMany((mi, wasDeclared) =>
        {
            var propertyType = mi.GetPropertyOrFieldType();

            return ModelInspector.IsEntity(propertyType);
        });
于 2012-11-12T09:06:31.483 回答