コード例 #1
0
        /**
         * Given a PropertyInfo we will work out if it is a Many to One
         * relationship. For it to be a Many to One relationship, the current
         * TModel must have a property that is a List of a foreign type.
         */
        protected virtual Relation?IsManyToOne(PropertyInfo localProp)
        {
            // The relationship desciptor we will return
            // if we actually find a valid relationship.
            var relation = new Relation {
                Type = Relation.RelationType.MtoO
            };

            // Grab the local and foreign types.
            relation.LocalType   = localProp.DeclaringType;
            relation.ForeignType = localProp.PropertyType.GenericTypeArguments[0];

            // Grab the sql table names for both model types.
            relation = this.SetTableNames(relation);

            // Many to One relationships will always store
            // the foreign key in the foreign table.
            relation.ForeignKeyTableName = relation.ForeignTableName;

            // Get all local properties that are lists of the foreignType.
            var localProps = Model.Dynamic(relation.LocalType).MappedProps
                             .Where(lp => TypeMapper.IsListOfEntities(lp, relation.ForeignType)).ToList();

            // Get all foreign properties that are of the localType.
            var foreignProps = Model.Dynamic(relation.ForeignType).MappedProps
                               .Where(fp => fp.PropertyType == relation.LocalType).ToList();

            // If we can't find any matching properties on the foreign
            // side well we don't have a Many to One relationship.
            if (foreignProps.Count == 0)
            {
                return(null);
            }

            // If there is 1 local and 1 foreign property that reference each
            // other, we have a simple, everyday, Many to One relationship.
            if (localProps.Count == 1 && foreignProps.Count == 1)
            {
                relation.LocalProperty        = localProp;
                relation.ForeignProperty      = foreignProps[0];
                relation.ForeignKeyColumnName = relation.LocalTableNameSingular + "Id";
            }

            // If we have a single local property but no foreign property.
            // We have a "Lazy" or "One Way" Many to One relationship.
            //
            // > NOTE: I think I have decided that lazy relationships are
            // > a pain in the arse and should not be allowed...

            /*else if (localProps.Count == 1 && foreignProps.Count == 0)
             * {
             *  relation.LocalProperty = localProp;
             *  relation.ForeignProperty = null;
             *  relation.ForeignKeyColumnName = relation.LocalTableNameSingular + "Id";
             * }*/

            // If there are multiple properties that reference each other,
            // we need to create the foreign key based on the property name
            // instead. So that the relationships remains unique.
            else if (localProps.Count > 1 || foreignProps.Count > 1)
            {
                PropertyInfo foreignProp;

                // First lets check for any explictly set InversePropertyAttributes.
                var foreignInverseProp = localProp.GetCustomAttribute <InversePropertyAttribute>(false);
                if (foreignInverseProp != null)
                {
                    // Sweet the local property is telling is
                    // exactly which foreign property to use.
                    foreignProp = foreignProps.Single
                                  (
                        fp => fp.Name == foreignInverseProp.Value
                                  );
                }
                else
                {
                    // Lets see if any of the foreign properties have an
                    // InversePropertyAttribute that points to our
                    // local property.
                    foreignProp = foreignProps
                                  .Where(fp => fp.GetCustomAttribute <InversePropertyAttribute>(false) != null)
                                  .SingleOrDefault(fp => fp.GetCustomAttribute <InversePropertyAttribute>(false).Value == localProp.Name);
                }

                // Now lets attempt to find our inverse property by looking at the property names.
                if (foreignProp == null)
                {
                    // Determin the relationship link id.
                    relation.LinkIdentifier = localProp.Name.Replace
                                              (
                        relation.ForeignTableName, String.Empty
                                              );

                    // We should have at least one foreign
                    // property that contains the LinkIdentifier.
                    try
                    {
                        foreignProp = foreignProps.Single
                                      (
                            fp => fp.Name.Contains
                            (
                                relation.LinkIdentifier
                            )
                                      );
                    }
                    catch
                    {
                        // Okay so we couldn't find a matching property.
                        // We still have a ManyToOne relationship, its a Lazy One,
                        // that requires a unique foreign key column name.
                        //
                        // > NOTE: I think I have decided that lazy relationships
                        // > are a pain in the arse and should not be allowed...
                        //foreignProp = null;

                        // We couldn't find a matching property
                        // so we don't have a relationship.
                        return(null);
                    }
                }
                else
                {
                    // If the forgeign poroperty was found by means of a
                    // InversePropertyAttribute then we still need a
                    // LinkIdentifier so we need to make one.
                    relation.LinkIdentifier = localProp.Name + foreignProp.Name;
                }

                // Save both navigational properties.
                relation.LocalProperty   = localProp;
                relation.ForeignProperty = foreignProp;

                // Set the foreign key column name
                relation.ForeignKeyColumnName = relation.LocalTableNameSingular + relation.LinkIdentifier + "Id";
            }
            else
            {
                return(null);
            }

            // Finally return the relationship descriptor.
            return(relation);
        }
コード例 #2
0
        /**
         * Given a PropertyInfo we will work out if it is a One to Many
         * relationship. For it to be a One to Many relationship, the current
         * "TModel" must have a property that refers to a single foreign type
         * and the foreign type must have a property that is a List of "TModel".
         */
        public Relation?IsOneToMany(PropertyInfo localProp)
        {
            // The relationship desciptor we will return
            // if we actually find a valid relationship.
            var relation = new Relation {
                Type = Relation.RelationType.OtoM
            };

            // Grab the local and foreign types.
            relation.LocalType   = localProp.DeclaringType;
            relation.ForeignType = localProp.PropertyType;

            // Grab the sql table names for both model types.
            relation = this.SetTableNames(relation);

            // One to Many relationships will always store
            // the foreign key in the local table.
            relation.ForeignKeyTableName = relation.LocalTableName;

            // Get all local properties that are of the foreign type.
            var localProps = Model.Dynamic(relation.LocalType).MappedProps
                             .Where(lp => lp.PropertyType == relation.ForeignType).ToList();

            // Get all foreign properties that are lists of the local type.
            var foreignProps = Model.Dynamic(relation.ForeignType).MappedProps
                               .Where(fp => TypeMapper.IsListOfEntities(fp, relation.LocalType)).ToList();

            // If we can't find any matching properties on the foreign
            // side well we don't have a One to Many relationship.
            if (foreignProps.Count == 0)
            {
                return(null);
            }

            // If there is only 1 local and 1 foreign property that refrence
            // each other then we create the foreign key based on the model
            // names. This is a simple every day One to Many relationship.
            else if (localProps.Count == 1 && foreignProps.Count == 1)
            {
                // Save both navigational properties.
                relation.LocalProperty   = localProp;
                relation.ForeignProperty = foreignProps[0];

                // Set the foreign key column name
                relation.ForeignKeyColumnName = relation.ForeignTableNameSingular + "Id";
            }

            // If there are multiple properties that reference each other,
            // we need to create the foreign key based on the property name
            // instead. So that the relationships remains unique.
            else if (localProps.Count > 1 || foreignProps.Count > 1)
            {
                PropertyInfo foreignProp;

                // First lets check for any explictly set InversePropertyAttributes.
                var foreignInverseProp = localProp.GetCustomAttribute <InversePropertyAttribute>(false);
                if (foreignInverseProp != null)
                {
                    // Sweet the local property is telling is
                    // exactly which foreign property to use.
                    foreignProp = foreignProps.Single
                                  (
                        fp => fp.Name == foreignInverseProp.Value
                                  );
                }
                else
                {
                    // Lets see if any of the foreign properties have an
                    // InversePropertyAttribute that points to our
                    // local property.
                    foreignProp = foreignProps
                                  .Where(fp => fp.GetCustomAttribute <InversePropertyAttribute>(false) != null)
                                  .SingleOrDefault(fp => fp.GetCustomAttribute <InversePropertyAttribute>(false).Value == localProp.Name);
                }

                // Now lets attempt to find our inverse property by looking at the property names.
                if (foreignProp == null)
                {
                    // Determin the relationship link id.
                    relation.LinkIdentifier = localProp.Name.Replace
                                              (
                        relation.ForeignTableNameSingular, String.Empty
                                              );

                    // We should have at least one foreign
                    // property that contains the LinkIdentifier.
                    try
                    {
                        foreignProp = foreignProps.Single
                                      (
                            fp => fp.Name.Contains
                            (
                                relation.LinkIdentifier
                            )
                                      );
                    }
                    catch
                    {
                        // We couldn't find a matching property
                        // so we don't have a relationship.
                        return(null);
                    }
                }
                else
                {
                    // If the forgeign poroperty was found by means of a
                    // InversePropertyAttribute then we still need a
                    // LinkIdentifier so we need to make one.
                    relation.LinkIdentifier = localProp.Name + foreignProp.Name;
                }

                // Save both navigational properties.
                relation.LocalProperty   = localProp;
                relation.ForeignProperty = foreignProp;

                // Set the foreign key column name
                relation.ForeignKeyColumnName = relation.ForeignTableNameSingular + relation.LinkIdentifier + "Id";
            }
            else
            {
                return(null);
            }

            // Finally return the relationship descriptor.
            return(relation);
        }
コード例 #3
0
        /**
         * Given a PropertyInfo we will work out if it is a Many to Many
         * relationship. For it to be a Many to Many relationship, both the
         * current TModel and the related TModel must have a List of each
         * others type.
         */
        protected virtual Relation?IsManyToMany(PropertyInfo localProp)
        {
            // The relationship desciptor we will return
            // if we actually find a valid relationship.
            var relation = new Relation {
                Type = Relation.RelationType.MtoM
            };

            // Grab the local and foreign types.
            relation.LocalType   = localProp.DeclaringType;
            relation.ForeignType = localProp.PropertyType.GenericTypeArguments[0];

            // Grab the sql table names for both model types.
            relation = this.SetTableNames(relation);

            // Get all local properties that are lists of the foreignType.
            var localProps = Model.Dynamic(relation.LocalType).MappedProps
                             .Where(lp => TypeMapper.IsListOfEntities(lp, relation.ForeignType)).ToList();

            // Get all foreign properties that are lists of the localType.
            var foreignProps = Model.Dynamic(relation.ForeignType).MappedProps
                               .Where(fp => TypeMapper.IsListOfEntities(fp, relation.LocalType)).ToList();

            // The next part of the logic will determin these values.
            string pivotTableName = null; string pivotTableNameAlt = null;

            // If we can't find any matching properties on the foreign
            // side well we don't have a Many to Many relationship.
            if (foreignProps.Count == 0)
            {
                return(null);
            }

            // If there is only 1 local and 1 foreign property that reference
            // each other then we create the pivot table based on the model
            // names. This is a simple every day Many to Many relationship.
            else if (localProps.Count == 1 && foreignProps.Count == 1)
            {
                // Save both navigational properties.
                relation.LocalProperty   = localProp;
                relation.ForeignProperty = foreignProps[0];

                // Create the pivot table name candiates.
                pivotTableName    = relation.LocalTableName + "To" + relation.ForeignTableName;
                pivotTableNameAlt = relation.ForeignTableName + "To" + relation.LocalTableName;
            }

            // This supports the ability to define multiple relationships to the
            // same type. If there are multiple properties that reference each
            // other, we use the property names to create a unique pivot table.
            else if (localProps.Count > 1 || foreignProps.Count > 1)
            {
                PropertyInfo foreignProp;

                // First lets check for any explictly set InversePropertyAttributes.
                var foreignInverseProp = localProp.GetCustomAttribute <InversePropertyAttribute>(false);
                if (foreignInverseProp != null)
                {
                    // Sweet the local property is telling is
                    // exactly which foreign property to use.
                    foreignProp = foreignProps.Single
                                  (
                        fp => fp.Name == foreignInverseProp.Value
                                  );
                }
                else
                {
                    // Lets see if any of the foreign properties have an
                    // InversePropertyAttribute that points to our
                    // local property.
                    foreignProp = foreignProps
                                  .Where(fp => fp.GetCustomAttribute <InversePropertyAttribute>(false) != null)
                                  .SingleOrDefault(fp => fp.GetCustomAttribute <InversePropertyAttribute>(false).Value == localProp.Name);
                }

                // Now lets attempt to find our inverse property by looking at the property names.
                if (foreignProp == null)
                {
                    // Determin the relation link id.
                    relation.LinkIdentifier = localProp.Name.Replace
                                              (
                        relation.ForeignTableName, String.Empty
                                              );

                    // We should have at least one foreign
                    // property that contains the LinkIdentifier.

                    try
                    {
                        foreignProp = foreignProps.Single
                                      (
                            fp => fp.Name.Contains
                            (
                                relation.LinkIdentifier
                            )
                                      );
                    }
                    catch
                    {
                        // We couldn't find a matching property
                        // so we don't have a relationship.
                        return(null);
                    }
                }
                else
                {
                    // If the forgeign poroperty was found by means of a
                    // InversePropertyAttribute then we still need a
                    // LinkIdentifier so we need to make one.
                    relation.LinkIdentifier = localProp.Name + foreignProp.Name;
                }

                // Save both navigational properties.
                relation.LocalProperty   = localProp;
                relation.ForeignProperty = foreignProp;

                // Create the pivot table name candiates.
                pivotTableName    = relation.LocalTableName + relation.LinkIdentifier + relation.ForeignTableName;
                pivotTableNameAlt = relation.ForeignTableName + relation.LinkIdentifier + relation.LocalTableName;
            }
            else
            {
                return(null);
            }

            // Now there are 2 possible pivot table names.
            // It's a first in, first served situation.
            if (this.PivotTableTaken(pivotTableName))
            {
                relation.PivotTableName             = pivotTableName;
                relation.PivotTableFirstColumnName  = relation.LocalTableNameSingular + "Id";
                relation.PivotTableSecondColumnName = relation.ForeignTableNameSingular + "Id";
            }
            else if (this.PivotTableTaken(pivotTableNameAlt))
            {
                relation.PivotTableName             = pivotTableNameAlt;
                relation.PivotTableFirstColumnName  = relation.ForeignTableNameSingular + "Id";
                relation.PivotTableSecondColumnName = relation.LocalTableNameSingular + "Id";
            }
            else
            {
                // No table actually exists yet,
                // so just go with the first option.
                // The Migrator will soon create it :)
                relation.PivotTableName             = pivotTableName;
                relation.PivotTableFirstColumnName  = relation.LocalTableNameSingular + "Id";
                relation.PivotTableSecondColumnName = relation.ForeignTableNameSingular + "Id";
            }

            // Finally return the relationship discriptor.
            return(relation);
        }