コード例 #1
0
        public ReflectionTable(IRelationalDatabase database, IDatabaseDialect dialect, Type tableType)
        {
            Database     = database ?? throw new ArgumentNullException(nameof(database));
            Dialect      = dialect ?? throw new ArgumentNullException(nameof(dialect));
            InstanceType = tableType ?? throw new ArgumentNullException(nameof(tableType));
            Name         = Dialect.GetQualifiedNameOrDefault(database, InstanceType);
            TypeProvider = new ReflectionTableTypeProvider(Dialect, InstanceType);

            _columns         = new Lazy <IReadOnlyList <IDatabaseColumn> >(LoadColumnList);
            _checkLookup     = new Lazy <IReadOnlyDictionary <Identifier, IDatabaseCheckConstraint> >(LoadChecks);
            _uniqueKeyLookup = new Lazy <IReadOnlyDictionary <Identifier, IDatabaseKey> >(LoadUniqueKeys);
            _indexLookup     = new Lazy <IReadOnlyDictionary <Identifier, IDatabaseIndex> >(LoadIndexes);
            _parentKeyLookup = new Lazy <IReadOnlyDictionary <Identifier, IDatabaseRelationalKey> >(LoadParentKeys);
            _childKeys       = new Lazy <IReadOnlyCollection <IDatabaseRelationalKey> >(LoadChildKeys);
            _primaryKey      = new Lazy <Option <IDatabaseKey> >(LoadPrimaryKey);
        }
コード例 #2
0
        // TODO: see if it's possible to create a foreign key to a synonym in sql server
        //       this should be possible in oracle but not sure
        private IReadOnlyDictionary <Identifier, IDatabaseRelationalKey> LoadParentKeys()
        {
            var result = new Dictionary <Identifier, IDatabaseRelationalKey>();

            var parentKeys = TypeProvider.ParentKeys;

            if (parentKeys.Empty())
            {
                return(result);
            }

            foreach (var declaredParentKey in parentKeys)
            {
                var fkColumns = declaredParentKey.Columns.Select(GetColumn).ToList();

                var parentName   = Dialect.GetQualifiedNameOrDefault(Database, declaredParentKey.TargetType);
                var parentOption = Database.GetTable(parentName);
                if (parentOption.IsNone.ConfigureAwait(false).GetAwaiter().GetResult())
                {
                    throw new Exception("Could not find parent table with name: " + parentName.ToString());
                }

                var tmpOption = parentOption.ToOption().ConfigureAwait(false).GetAwaiter().GetResult();
                var parent    = tmpOption.MatchUnsafe(t => t, () => null !);

                var parentTypeProvider = new ReflectionTableTypeProvider(Dialect, declaredParentKey.TargetType);
                var parentInstance     = parentTypeProvider.TableInstance;
                var keyObject          = declaredParentKey.KeySelector(parentInstance);
                var parentKeyName      = Dialect.GetAliasOrDefault(keyObject.Property !);

                IDatabaseKey parentKey;
                if (keyObject.KeyType == DatabaseKeyType.Primary)
                {
                    // TODO: provide better error messaging, maybe to KeyNotFoundException too?
                    parentKey = parent.PrimaryKey
                                .Match(pk => pk, () => throw new Exception("Could not find matching parent key for foreign key."));
                }
                else if (keyObject.KeyType == DatabaseKeyType.Unique)
                {
                    var uniqueKey = parent.UniqueKeys.FirstOrDefault(uk =>
                                                                     uk.Name.Where(ukName => ukName.LocalName == parentKeyName).IsSome
                                                                     );
                    parentKey = uniqueKey ?? throw new Exception("Could not find matching parent key for foreign key.");
                }
                else
                {
                    throw new Exception("Cannot point a foreign key to a key that is not the primary key or a unique key."); // TODO: improve error messaging
                }

                // check that columns match up with parent key -- otherwise will fail
                // TODO: don't assume that the FK is to a table -- could be to a synonym
                //       maybe change interface of Synonym<T> to be something like Synonym<Table<T>> or Synonym<Synonym<T>> -- could unwrap at runtime?
                var childKeyName = Dialect.GetAliasOrDefault(declaredParentKey.Property !);
                var childKey     = new ReflectionForeignKey(childKeyName, parentKey, fkColumns);

                var deleteAttr   = Dialect.GetDialectAttribute <OnDeleteActionAttribute>(declaredParentKey.Property !);
                var deleteAction = deleteAttr?.Action ?? ReferentialAction.NoAction;

                var updateAttr   = Dialect.GetDialectAttribute <OnUpdateActionAttribute>(declaredParentKey.Property !);
                var updateAction = updateAttr?.Action ?? ReferentialAction.NoAction;

                childKey.Name.IfSome(name => result[name.LocalName] = new ReflectionRelationalKey(Name, childKey, parent.Name, parentKey, deleteAction, updateAction));
            }

            return(result);
        }