Exemple #1
0
        private void SetKeys(string keys, SqlNamingMapper mapper, Type dataMappingType)
        {
            if (keys != null)
            {
                // from constructor
                keys = DataContract.Map(AutoMap.Keys, keys);
            }
            else if (DataContract.KeyColumns != null)
            {
                // from attributes
                keys = DataContract.KeyColumns;
            }
            else
            {
                // from mapper
                PrimaryKeyField = mapper.GetPrimaryKeyFieldNames(dataMappingType);
                keys            = DataContract.Map(AutoMap.On, PrimaryKeyField);
            }

            if (keys == null)
            {
                PrimaryKeyColumnList = new List <string>();
            }
            else
            {
                PrimaryKeyColumn = keys;
                if (PrimaryKeyField == null)
                {
                    PrimaryKeyField = DataContract.ReverseMap(PrimaryKeyColumn);
                }
                PrimaryKeyColumnList = keys.Split(',').Select(k => k.Trim()).ToList();
            }
        }
Exemple #2
0
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="isGeneric"></param>
        /// <param name="type"></param>
        /// <param name="columns"></param>
        /// <param name="mapper"></param>
        internal DataContractKey(bool isGeneric, Type type, string columns, SqlNamingMapper mapper)
        {
            IsGeneric = isGeneric;

            foreach (var attr in type
#if !NETFRAMEWORK
                     .GetTypeInfo()
#endif
                     .GetCustomAttributes(false))
            {
                if (attr is DatabaseTableAttribute)
                {
                    DatabaseTableSettings = (DatabaseTableAttribute)attr;
                }
            }

            // TO DO: Should we really be calling the mapper in the data contract *key* constructor?
            // (Whatever calls are made here are called *every time* we check whether we already have a contract.)
            if (DatabaseTableSettings == null)
            {
                // we don't ever need to look up the mapper values if they have been overridden by the user-attribute;
                // these will be from the user-mapper if defined, or the default mapper if not
                DatabaseTableSettings = new DatabaseTableAttribute(
                    mapper.TableNameMapping(type),
                    mapper.CaseSensitiveColumns(type),
                    mapper.AutoMap(type));
            }

            HasMapperColumnsMapping =
                mapper.ColumnNameMapping != SqlNamingMapper.IdentityColumnMapping ||
                mapper.ColumnDataDirection != SqlNamingMapper.ColumnDataDirectionUnspecified ||
                mapper.IgnoreColumn != SqlNamingMapper.NeverIgnoreColumn;

            // If the user is trying to map column names in a dynamic instance of Mighty, then there must be a columns spec and columns auto-mapping must be left on
            if (!IsGeneric && HasMapperColumnsMapping)
            {
                if (columns == null || columns == "*")
                {
                    throw new InvalidOperationException($"You must provide an explicit `columns` specification to any dynamic instance of {nameof(MightyOrm)} with column name mapping");
                }
                if ((DatabaseTableSettings.AutoMap & AutoMap.Columns) == 0)
                {
                    throw new InvalidOperationException($"You must enable {nameof(AutoMap)}.{nameof(AutoMap.Columns)} in your {nameof(DatabaseTableSettings.AutoMap)} settings for any dynamic instance of {nameof(MightyOrm)} with column name mapping");
                }
                // Columns is not needed in the data contract except if we're here;
                // where needed, normalise it to improve caching
                DynamicColumnSpec = NormaliseColumns(columns);
            }

            ColumnName          = mapper.ColumnNameMapping;
            ColumnDataDirection = mapper.ColumnDataDirection;
            IgnoreColumn        = mapper.IgnoreColumn;

            DataItemType = type;

            DynamicNullContract = !IsGeneric && DynamicColumnSpec == null;
        }
Exemple #3
0
        /// <summary>
        /// Get (from store, or creating the first time it is needed) data contract for the type, columns spec and data mapper.
        /// </summary>
        /// <param name="IsGeneric"></param>
        /// <param name="type"></param>
        /// <param name="columns"></param>
        /// <param name="mapper"></param>
        /// <returns></returns>
        /// <remarks>
        /// In theory, mapping depends on Plugin, Factory, and ConnectionString as well;
        /// in practice, including those would make it much harder to provide the very useful
        /// <see cref="DataContract.Map(string)"/> feature.
        /// I think it seems (more or less?) reasonable to suppose that any one class will only
        /// be read from and written one database with one mapping at a time? In fact, since
        /// Mighty only supports one mapping per class, maybe this is effectively enforced anyway?
        /// </remarks>
        internal DataContract Get(bool IsGeneric, Type type, string columns, SqlNamingMapper mapper)
        {
            DataContractKey key = new DataContractKey(IsGeneric, type, columns, mapper);

            CacheHits++;
            return(store.GetOrAdd(key, k => {
                CacheHits--;
                CacheMisses++;
                return new DataContract(k);
            }));
        }
Exemple #4
0
 /// <summary>
 /// Manage key(s) and sequence or identity.
 /// </summary>
 /// <param name="IsGeneric"></param>
 /// <param name="dataContract"></param>
 /// <param name="xplugin"></param>
 /// <param name="dataMappingType"></param>
 /// <param name="xmapper"></param>
 /// <param name="keyNames"></param>
 /// <param name="sequence"></param>
 internal PrimaryKeyInfo(
     bool IsGeneric, DataContract dataContract, PluginBase xplugin, Type dataMappingType, SqlNamingMapper xmapper,
     string keyNames, string sequence)
 {
     Plugin          = xplugin;
     SqlNamingMapper = xmapper;
     DataItemType    = dataContract.Key.DataItemType;
     DataContract    = dataContract;
     SetKeys(keyNames, xmapper, dataMappingType);
     SetSequence(xplugin, xmapper, sequence);
     SetPkMemberInfo(IsGeneric, dataContract);
 }
Exemple #5
0
        /// <summary>
        /// Get (from store, or creating the first time it is needed) data contract for the type, columns spec and data mapper.
        /// </summary>
        /// <param name="IsGeneric"></param>
        /// <param name="type"></param>
        /// <param name="columns"></param>
        /// <param name="mapper"></param>
        /// <returns></returns>
        /// <remarks>
        /// In theory, mapping depends on Plugin, Factory, and ConnectionString as well;
        /// in practice, including those would make it much harder to provide the very useful
        /// <see cref="DataContract.Map(string)"/> feature.
        /// I think it seems (more or less?) reasonable to suppose that any one class will only
        /// be read from and written one database with one mapping at a time? In fact, since
        /// Mighty only supports one mapping per class, maybe this is effectively enforced anyway?
        /// </remarks>
        internal DataContract Get(bool IsGeneric, Type type, string columns, SqlNamingMapper mapper)
        {
            DataContractKey key = new DataContractKey(IsGeneric, type, columns, mapper);
            DataContract    value;

            if (store.TryGetValue(key, out value))
            {
                CacheHits++;
            }
            else
            {
                CacheMisses++;
                value = new DataContract(key);
                store.Add(key, value);
            }
            return(value);
        }
Exemple #6
0
        private void SetSequence(PluginBase plugin, SqlNamingMapper mapper, string sequence)
        {
            // At the end of this next block of code, SequenceNameOrIdentityFunction should only be non-null if we
            // are actually expecting to use it later (which entails a simple (single column) PK).

            // It makes no sense to attempt to retrieve an auto-generated value for a compund primary key.
            if (PrimaryKeyColumnList.Count != 1)
            {
                // No exception here if database is identity-based since we want to allow, e.g., an override
                // of `sequence: "@@IDENTITY"` on all instances of Mighty, even if some instances are then
                // used for tables with no or compound primary keys.
                if (plugin.IsSequenceBased && !string.IsNullOrEmpty(sequence))
                {
                    throw new InvalidOperationException($"It is not possible to specify a sequence name for a table with {(PrimaryKeyColumnList.Count > 1 ? "a compound (multi-column)" : "no")} primary key");
                }
                SequenceNameOrIdentityFunction = null;
            }
            else
            {
                if (sequence == "")
                {
                    // empty string specifies that PK is manually controlled
                    SequenceNameOrIdentityFunction = null;
                }
                else
                {
                    if (plugin.IsSequenceBased)
                    {
                        // sequence-based, non-null, non-empty specifies sequence name
                        SequenceNameOrIdentityFunction = sequence ?? mapper.QuoteDatabaseIdentifier(sequence);
                    }
                    else
                    {
                        // identity-based, non-null, non-empty specifies non-default identity retrieval function (e.g. use "@@IDENTITY" on SQL CE)
                        SequenceNameOrIdentityFunction = sequence != null ? sequence : plugin.IdentityRetrievalFunction;
                    }
                }
            }
        }