Exemplo n.º 1
0
        public Conventions(Func <Type, Action <IIdMapper> > idMapper = null)
        {
            _entitiesToMap = new List <Type>();

            var lazyRelation = Enum.TryParse(ConfigurationManager.AppSettings["NhConventions:DefaultLazyRelation"],
                                             out HbmLaziness parsed)
                ? parsed
                : (HbmLaziness?)null;

            _defaultLazyRelation = lazyRelation.HasValue
                ? lazyRelation == HbmLaziness.NoProxy
                    ? LazyRelation.NoProxy
                    : lazyRelation == HbmLaziness.Proxy
                        ? LazyRelation.Proxy
                        : LazyRelation.NoLazy
                : null;

            _idMapper = idMapper ?? (t =>
            {
                if (t == typeof(Int64) || t == typeof(int))
                {
                    return(id =>
                    {
                        id.Generator(NHGens.HighLow, g => g.Params(new { table = "Frwk_HiLoSequences", sequence = "FrameworkSequence", column = "NextValue", max_lo = "100" }));
                    });
                }
                else if (t == typeof(Guid))
                {
                    return(id =>
                    {
                        id.Generator(new GuidAssignedGeneratorDef());
                    });
                }

                return(null);
            });

            _defaultMapper        = new ModelMapperWithNamingConventions();
            DefaultModelInspector = _defaultMapper.ModelInspector;
        }
Exemplo n.º 2
0
        public void Compile(NHcfg.Configuration configuration)
        {
            var mapper = new ModelMapperWithNamingConventions();

            mapper.IsEntity((type, declared) => MappingHelper.IsEntity(type));
            mapper.IsRootEntity((type, declared) => MappingHelper.IsRootEntity(type));
            mapper.IsTablePerClass((type, declared) =>
            {
                var discriminator = MappingHelper.GetDiscriminatorColumn(type);
                return(string.IsNullOrWhiteSpace(discriminator));
            });
            mapper.IsTablePerClassHierarchy((type, declared) =>
            {
                var discriminator = MappingHelper.GetDiscriminatorColumn(type);
                return(!string.IsNullOrWhiteSpace(discriminator));
            });
            mapper.IsTablePerConcreteClass((type, declared) => false);

            mapper.IsOneToMany((mi, declared) =>
            {
                if (Attribute.IsDefined(mi, (typeof(ManyToManyAttribute))))
                {
                    return(false);
                }

                return(declared || _defaultMapper.ModelInspector.IsOneToMany(mi));
            });

            mapper.IsManyToMany((mi, declared) =>
            {
                if (Attribute.IsDefined(mi, (typeof(ManyToManyAttribute))))
                {
                    return(true);
                }

                return(declared || _defaultMapper.ModelInspector.IsManyToAny(mi));
            });

            mapper.IsPersistentProperty((mi, declared) =>
            {
                if (!NhMappingHelper.IsPersistentProperty(mi))
                {
                    return(false);
                }

                return(_defaultMapper.ModelInspector.IsPersistentProperty(mi));
            });

            mapper.BeforeMapSubclass += (modelInspector, type, subclassCustomizer) =>
            {
                var discriminatorValue = MappingHelper.GetDiscriminatorValue(type);

                subclassCustomizer.DiscriminatorValue(discriminatorValue);


                var joinPropAttribute = type.GetAttribute <JoinedPropertyAttribute>();
                if (joinPropAttribute != null)
                {
                    if (string.IsNullOrWhiteSpace(joinPropAttribute.TableName))
                    {
                        throw new Exception($"{nameof(JoinedPropertyAttribute.TableName)} is mandatory for `{joinPropAttribute.GetType().Name}`, check class `{type.FullName}`");
                    }

                    if (subclassCustomizer is NMIMPL.SubclassMapper subclassMapper)
                    {
                        // add join with provided table name, all properties will be added using current conventions and placed to the corresponding group using SplitGroupId = TableName
                        subclassMapper.Join(joinPropAttribute.TableName, j =>
                        {
                            j.Table(joinPropAttribute.TableName);

                            j.Fetch(FetchKind.Join);

                            j.Key(k =>
                            {
                                k.Column("Id");
                            });
                        });
                    }
                }
            };

            mapper.SplitsFor((type, definedSplits) =>
            {
                var splits = definedSplits.ToList();

                if (type.Name.Contains("TestProcessConfiguration"))
                {
                }

                var joinPropAttribute = type.GetAttribute <JoinedPropertyAttribute>();
                if (joinPropAttribute != null && !splits.Contains(joinPropAttribute.TableName))
                {
                    splits.Add(joinPropAttribute.TableName);
                }

                return(splits);
            });

            mapper.IsTablePerClassSplit((definition, b) => true);

            mapper.BeforeMapElement += (modelInspector, member, collectionRelationElementCustomizer) =>
            {
            };

            mapper.BeforeMapProperty += (modelInspector, member, propertyCustomizer) =>
            {
                var propertyType = member.LocalMember.GetPropertyOrFieldType();

                var    columnName = MappingHelper.GetColumnName(member.LocalMember);
                string sqlType    = null;
                IType  columnType = null;

                if (propertyType == typeof(DateTime) || propertyType == typeof(DateTime?))
                {
                    columnType = NHibernateUtil.DateTime;
                    sqlType    = "DateTime";
                }
                else
                if (member.LocalMember.GetAttribute <StringLengthAttribute>()?.MaximumLength == int.MaxValue)
                //if (Attribute.IsDefined(member.LocalMember, (typeof(StringClobAttribute))))
                {
                    columnType = NHibernateUtil.StringClob;
                    sqlType    = "nvarchar(max)";
                }

                if (columnType != null)
                {
                    propertyCustomizer.Type(columnType);
                }

                if (Attribute.GetCustomAttribute(member.LocalMember, typeof(ReadonlyPropertyAttribute), true) is ReadonlyPropertyAttribute readonlyAttribute)
                {
                    propertyCustomizer.Insert(readonlyAttribute.Insert);
                    propertyCustomizer.Update(readonlyAttribute.Update);
                }

                propertyCustomizer.Column(c =>
                {
                    c.Name(columnName);
                    if (!string.IsNullOrWhiteSpace(sqlType))
                    {
                        c.SqlType(sqlType);
                    }
                });
            };

            mapper.IsPersistentId((mi, d) =>
            {
                var isId = mi.Name.Equals("Id", StringComparison.InvariantCultureIgnoreCase);
                return(isId);
            });
            mapper.BeforeMapClass += (modelInspector, type, classCustomizer) =>
            {
                var tableName = MappingHelper.GetTableName(type);

                classCustomizer.Table(tableName);

                var imMutable = type.HasAttribute <ImMutableAttribute>(true);
                if (imMutable)
                {
                    classCustomizer.Mutable(false);
                }

                if (MappingHelper.IsEntity(type))
                {
                    try
                    {
                        var idProp = type.GetProperty("Id");
                        if (idProp != null)
                        // note: Id may be missing when entity has hand-written mapping but isn't derived from EntityWithTypedId<> (for example: NhIdentityUserLogin)
                        {
                            if (tableName.StartsWith("Abp") && (idProp.PropertyType == typeof(Int64) || idProp.PropertyType == typeof(int)))
                            {
                                // temporary map `Abp` tables without hilo
                                classCustomizer.Id(p =>
                                {
                                    p.Column("Id");
                                    p.Generator(NHGens.Identity);
                                });
                            }
                            else
                            {
                                var idColumn = idProp.GetAttribute <ColumnAttribute>()?.Name ?? "Id";

                                // get Id mapper
                                var idMapper = _idMapper.Invoke(idProp.PropertyType);
                                if (idMapper != null)
                                {
                                    classCustomizer.Id(p =>
                                    {
                                        idMapper.Invoke(p);
                                        p.Column(idColumn);
                                    });
                                }
                            }
                        }
                        else
                        {
                        }
                    }
                    catch (Exception e)
                    {
                        throw;
                    }
                }

                var discriminatorColumn = MappingHelper.GetDiscriminatorColumn(type);
                if (!string.IsNullOrWhiteSpace(discriminatorColumn))
                {
                    classCustomizer.Discriminator(d =>
                    {
                        d.Column(discriminatorColumn);

                        if (MappingHelper.GetFilterUnknownDiscriminatorsFlag(type))
                        {
                            d.Force(true);
                        }
                    });

                    var discriminatorValue = MappingHelper.GetDiscriminatorValue(type);

                    classCustomizer.DiscriminatorValue(discriminatorValue);
                }

                // IMayHaveTenant support
                if (typeof(IMayHaveTenant).IsAssignableFrom(type))
                {
                    classCustomizer.Filter("MayHaveTenant", m =>
                    {
                    });
                }

                // ISoftDelete support
                if (typeof(ISoftDelete).IsAssignableFrom(type))
                {
                    classCustomizer.Filter("SoftDelete", m =>
                    {
                    });
                }
            };

            mapper.BeforeMapManyToOne += (modelInspector, propertyPath, map) =>
            {
                string columnPrefix = MappingHelper.GetColumnPrefix(propertyPath.LocalMember.DeclaringType);

                var lazyAttribute = propertyPath.LocalMember.GetAttribute <LazyAttribute>(true);
                var lazyRelation  = lazyAttribute != null?lazyAttribute.GetLazyRelation() : _defaultLazyRelation;

                if (lazyRelation != null)
                {
                    map.Lazy(lazyRelation);
                }

                var foreignKeyAttribute = propertyPath.LocalMember.GetAttribute <ForeignKeyAttribute>(true);
                var foreignKeyColumn    = foreignKeyAttribute != null
                    ? foreignKeyAttribute.Name
                    : columnPrefix + propertyPath.LocalMember.Name + "Id";

                //map.NotFound(NotFoundMode.Ignore); disabled due to performance issues, this option breaks lazy loading
                map.Column(foreignKeyColumn);

                var directlyMappedFk = propertyPath.LocalMember.DeclaringType?.GetProperty(foreignKeyColumn);

                if (foreignKeyColumn.ToLower() == "id" || directlyMappedFk != null)
                {
                    map.Insert(false);
                    map.Update(false);
                }

                var cascadeAttribute = propertyPath.LocalMember.GetAttribute <CascadeAttribute>(true);
                map.Cascade(cascadeAttribute?.Cascade ?? Cascade.Persist);
                map.Class(propertyPath.LocalMember.GetPropertyOrFieldType());
            };

            mapper.BeforeMapBag += (modelInspector, propertyPath, map) => {
                var inversePropertyAttribute = propertyPath.LocalMember.GetAttribute <InversePropertyAttribute>(true);
                if (inversePropertyAttribute != null)
                {
                    map.Key(keyMapper => keyMapper.Column(inversePropertyAttribute.Property));
                }
                else
                {
                    map.Key(keyMapper => keyMapper.Column(propertyPath.GetContainerEntity(modelInspector).Name + "Id"));
                }

                map.Cascade(Cascade.All);
                map.Lazy(CollectionLazy.Lazy);

                var bagMapper = map as NMIMPL.BagMapper;

                var manyToManyAttribute = propertyPath.LocalMember.GetAttribute <ManyToManyAttribute>(true);

                if (manyToManyAttribute != null)
                {
                    map.Cascade(Cascade.None);

                    if (!string.IsNullOrEmpty(manyToManyAttribute.Table))
                    {
                        map.Table(manyToManyAttribute.Table);
                    }

                    if (!string.IsNullOrEmpty(manyToManyAttribute.KeyColumn))
                    {
                        map.Key(keyMapper => keyMapper.Column(manyToManyAttribute.KeyColumn));
                    }
                    if (!string.IsNullOrEmpty(manyToManyAttribute.Where))
                    {
                        map.Where(manyToManyAttribute.Where);
                    }
                    if (!string.IsNullOrEmpty(manyToManyAttribute.OrderBy))
                    {
                        map.OrderBy(manyToManyAttribute.OrderBy);
                    }
                }
                else
                {
                    if (bagMapper != null && typeof(ISoftDelete).IsAssignableFrom(bagMapper.ElementType))
                    {
                        //TODO: Check IsDeletedColumn for Many-To-Many
                        map.Where($"{SheshaDatabaseConsts.IsDeletedColumn} = 0");
                    }
                }
            };

            mapper.BeforeMapManyToMany += (modelInspector, propertyPath, map) => {
                //map.NotFound(NotFoundMode.Ignore); disabled due to performance issues, this option breaks lazy loading

                var manyToManyAttribute = propertyPath.LocalMember.GetAttribute <ManyToManyAttribute>(true);
                if (manyToManyAttribute != null)
                {
                    if (!string.IsNullOrEmpty(manyToManyAttribute.ChildColumn))
                    {
                        map.Column(manyToManyAttribute.ChildColumn);
                    }
                }
            };

            foreach (var assembly in _assemblies)
            {
                var allTypes = !assembly.IsDynamic
                    ? assembly.GetExportedTypes()
                    : assembly.GetTypes();
                var allEntities = allTypes.Where(t => MappingHelper.IsEntity(t)).ToList();
                foreach (var entityType in allEntities)
                {
                    var classMapping = configuration.GetClassMapping(entityType);
                    if (classMapping == null)
                    {
                        _entitiesToMap.Add(entityType);
                    }
                }

                var mappingOverride = allTypes.Where(t => IsClassMapping(t) && !t.IsAbstract).ToList();
                foreach (var @override in mappingOverride)
                {
                    try
                    {
                        var entityType = GetEntityTypeByMapping(@override);

                        if (entityType.IsEntityType())
                        {
                            _defaultMapper.AddMapping(@override);
                            mapper.AddMapping(@override);

                            if (entityType != null && !entityType.IsAbstract && !_entitiesToMap.Contains(entityType))
                            {
                                _entitiesToMap.Add(entityType);
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        throw;
                    }
                }
            }

            // sort entity types by hierarchy
            _entitiesToMap = MappingHelper.SortEntityTypesByInheritance(_entitiesToMap);

            /* for debug
             * foreach (var ent in _entitiesToMap)
             * {
             *  try
             *  {
             *      var mapping1 = mapper.CompileMappingFor(new List<Type> { ent });
             *  }
             *  catch (Exception e)
             *  {
             *      throw;
             *  }
             * }
             */

            HbmMapping mapping = mapper.CompileMappingFor(_entitiesToMap);

            configuration.AddDeserializedMapping(mapping, "AutoMapping");

            LastCompiledXml = mapping.AsString();
        }