예제 #1
0
 /// <summary>
 /// Writes attach/detach method
 /// </summary>
 /// <param name="writer"></param>
 /// <param name="table"></param>
 /// <param name="schema"></param>
 /// <param name="context"></param>
 protected virtual void WriteClassChildrenAttachment(CodeWriter writer, Table table, Database schema, GenerationContext context)
 {
     var children = GetClassChildren(table).ToList();
     if (children.Count > 0)
     {
         using (writer.WriteRegion("Attachement handlers"))
         {
             foreach (var child in children)
             {
                 // the reverse child is the association seen from the child
                 // we're going to use it...
                 var reverseChild = schema.GetReverseAssociation(child);
                 // ... to get the parent name
                 var memberName = reverseChild.Member;
                 var entityParameter = new ParameterDefinition { Name = "entity", LiteralType = child.Type };
                 // the Attach event handler sets the child entity parent to "this"
                 using (writer.WriteMethod(SpecificationDefinition.Private, GetChildAttachMethodName(child),
                                           null, entityParameter))
                 {
                     writer.WriteLine(
                         writer.GetStatement(
                             writer.GetAssignmentExpression(
                                 writer.GetMemberExpression(entityParameter.Name, memberName),
                                 writer.GetThisExpression())));
                 }
                 writer.WriteLine();
                 // the Detach event handler sets the child entity parent to null
                 using (writer.WriteMethod(SpecificationDefinition.Private, GetChildDetachMethodName(child),
                                           null, entityParameter))
                 {
                     writer.WriteLine(
                         writer.GetStatement(
                             writer.GetAssignmentExpression(
                                 writer.GetMemberExpression(entityParameter.Name, memberName),
                                 writer.GetNullExpression())));
                 }
                 writer.WriteLine();
             }
         }
     }
 }
예제 #2
0
        void GenerateEntityParents(CodeTypeDeclaration entity, Table table, Database schema)
        {
            var parents = table.Type.Associations.Where(a => a.IsForeignKey);
            if (!parents.Any())
                return;

            var parentMembers = new List<CodeTypeMember>();

            foreach (var parent in parents)
            {
                bool hasDuplicates = (from p in parents where p.Member == parent.Member select p).Count() > 1;
                // WriteClassParent(writer, parent, hasDuplicates, schema, context);
                // the following is apparently useless
                DbLinq.Schema.Dbml.Table targetTable = schema.Tables.FirstOrDefault(t => t.Type.Name == parent.Type);
                if (targetTable == null)
                {
                    //Logger.Write(Level.Error, "ERROR L191 target table type not found: " + parent.Type + "  (processing " + parent.Name + ")");
                    continue;
                }

                string member = parent.Member;
                string storageField = GetStorageFieldName(parent);
                // TODO: remove this
                if (member == parent.ThisKey)
                {
                    member = parent.ThisKey + targetTable.Type.Name; //repeat name to prevent collision (same as Linq)
                    storageField = "_x_" + parent.Member;
                }

                var parentType = new CodeTypeReference(targetTable.Type.Name);
                entity.Members.Add(new CodeMemberField(new CodeTypeReference("EntityRef", parentType), storageField) {
                    InitExpression = new CodeObjectCreateExpression(new CodeTypeReference("EntityRef", parentType)),
                });

                var parentName = hasDuplicates
                    ? member + "_" + string.Join("", parent.TheseKeys.ToArray())
                    : member;
                var property = new CodeMemberProperty() {
                    Name        = parentName,
                    Type        = parentType,
                    Attributes  = ToMemberAttributes(parent),
                    CustomAttributes = {
                        new CodeAttributeDeclaration("Association",
                            new CodeAttributeArgument("Storage", new CodePrimitiveExpression(storageField)),
                            new CodeAttributeArgument("OtherKey", new CodePrimitiveExpression(parent.OtherKey)),
                            new CodeAttributeArgument("ThisKey", new CodePrimitiveExpression(parent.ThisKey)),
                            new CodeAttributeArgument("Name", new CodePrimitiveExpression(parent.Name)),
                            new CodeAttributeArgument("IsForeignKey", new CodePrimitiveExpression(parent.IsForeignKey))),
                        new CodeAttributeDeclaration("DebuggerNonUserCode"),
                    },
                };
                parentMembers.Add(property);
                property.GetStatements.Add(new CodeMethodReturnStatement(
                        new CodePropertyReferenceExpression(
                            new CodeFieldReferenceExpression(thisReference, storageField),
                            "Entity")));

                // algorithm is:
                // 1.1. must be different than previous value
                // 1.2. or HasLoadedOrAssignedValue is false (but why?)
                // 2. implementations before change
                // 3. if previous value not null
                // 3.1. place parent in temp variable
                // 3.2. set [Storage].Entity to null
                // 3.3. remove it from parent list
                // 4. assign value to [Storage].Entity
                // 5. if value is not null
                // 5.1. add it to parent list
                // 5.2. set FK members with entity keys
                // 6. else
                // 6.1. set FK members to defaults (null or 0)
                // 7. implementationas after change
                var otherAssociation = schema.GetReverseAssociation(parent);
                var parentEntity = new CodePropertyReferenceExpression(
                        new CodeFieldReferenceExpression(thisReference, storageField),
                        "Entity");
                var parentTable = schema.Tables.Single(t => t.Type.Associations.Contains(parent));
                var childKeys = parent.TheseKeys.ToArray();
                var childColumns = (from ck in childKeys select table.Type.Columns.Single(c => c.Member == ck))
                                    .ToArray();
                var parentKeys = parent.OtherKeys.ToArray();
                property.SetStatements.Add(new CodeConditionStatement(
                        // 1.1
                        ValuesAreNotEqual_Ref(parentEntity, new CodePropertySetValueReferenceExpression()),
                        // 2. TODO: code before the change
                        // 3. 
                        new CodeConditionStatement(
                            ValueIsNotNull(parentEntity),
                            // 3.1
                            new CodeVariableDeclarationStatement(parentType, "previous" + parent.Type, parentEntity),
                            // 3.2
                            new CodeAssignStatement(parentEntity, new CodePrimitiveExpression(null)),
                            // 3.3
                            new CodeExpressionStatement(
                                 new CodeMethodInvokeExpression(
                                    new CodeMethodReferenceExpression(
                                        new CodePropertyReferenceExpression(
                                            new CodeVariableReferenceExpression("previous" + parent.Type),
                                            otherAssociation.Member),
                                        "Remove"),
                                    thisReference))),
                        // 4.
                        new CodeAssignStatement(parentEntity, new CodePropertySetValueReferenceExpression()),
                        // 5. if value is null or not...
                        new CodeConditionStatement(
                            ValueIsNotNull(new CodePropertySetValueReferenceExpression()),
                            // 5.1
                            new CodeStatement[]{
                                new CodeExpressionStatement(
                                    new CodeMethodInvokeExpression(
                                        new CodeMethodReferenceExpression(
                                            new CodePropertyReferenceExpression(
                                                new CodePropertySetValueReferenceExpression(),
                                                otherAssociation.Member),
                                            "Add"),
                                        thisReference))
                            // 5.2
                            }.Concat(Enumerable.Range(0, parentKeys.Length).Select(i =>
                                (CodeStatement) new CodeAssignStatement(
                                    new CodeVariableReferenceExpression(GetStorageFieldName(childColumns[i])),
                                    new CodePropertyReferenceExpression(
                                        new CodePropertySetValueReferenceExpression(),
                                        parentKeys[i]))
                            )).ToArray(),
                            // 6.
                            Enumerable.Range(0, parentKeys.Length).Select(i => {
                                var column = parentTable.Type.Columns.Single(c => c.Member == childKeys[i]);
                                return (CodeStatement) new CodeAssignStatement(
                                    new CodeVariableReferenceExpression(GetStorageFieldName(childColumns[i])),
                                    column.CanBeNull
                                        ? (CodeExpression) new CodePrimitiveExpression(null)
                                        : (CodeExpression) new CodeDefaultValueExpression(new CodeTypeReference(column.Type)));
                            }).ToArray())
                        // 7: TODO
                ));
            }

            if (parentMembers.Count == 0)
                return;
            parentMembers.First().StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Parents"));
            parentMembers.Last().EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, null));
            entity.Members.AddRange(parentMembers.ToArray());
        }
예제 #3
0
        protected virtual void WriteClassParent(CodeWriter writer, Association parent, bool hasDuplicates, Database schema, GenerationContext context)
        {
            // the following is apparently useless
            DbLinq.Schema.Dbml.Table targetTable = schema.Tables.FirstOrDefault(t => t.Type.Name == parent.Type);
            if (targetTable == null)
            {
                //Logger.Write(Level.Error, "ERROR L191 target table type not found: " + parent.Type + "  (processing " + parent.Name + ")");
                return;
            }

            string member = parent.Member;
            string storageField = parent.Storage;
            // TODO: remove this
            if (member == parent.ThisKey)
            {
                member = parent.ThisKey + targetTable.Type.Name; //repeat name to prevent collision (same as Linq)
                storageField = "_x_" + parent.Member;
            }

            writer.WriteField(SpecificationDefinition.Private, storageField,
                              writer.GetGenericName(TypeExtensions.GetShortName(typeof(EntityRef<>)),
                                                    targetTable.Type.Name));

            var storageAttribute = NewAttributeDefinition<AssociationAttribute>();
			storageAttribute["Storage"] = storageField;
			storageAttribute["OtherKey"] = parent.OtherKey;
            storageAttribute["ThisKey"] = parent.ThisKey;
            storageAttribute["Name"] = parent.Name;
            storageAttribute["IsForeignKey"] = parent.IsForeignKey;

            SpecificationDefinition specifications;
            if (parent.AccessModifierSpecified)
                specifications = GetSpecificationDefinition(parent.AccessModifier);
            else
                specifications = SpecificationDefinition.Public;
            if (parent.ModifierSpecified)
                specifications |= GetSpecificationDefinition(parent.Modifier);

            var propertyName = hasDuplicates
                                   ? member + "_" + string.Join("", parent.TheseKeys.ToArray())
                                   : member;

            using (writer.WriteAttribute(storageAttribute))
            using (writer.WriteAttribute(NewAttributeDefinition<DebuggerNonUserCodeAttribute>()))
            using (writer.WriteProperty(specifications, propertyName, targetTable.Type.Name))
            {
                string storage = writer.GetMemberExpression(storageField, "Entity");
                using (writer.WritePropertyGet())
                {
                    writer.WriteLine(writer.GetReturnStatement(storage));
                }
                using (writer.WritePropertySet())
                {
                    // algorithm is:
                    // 1.1. must be different than previous value
                    // 1.2. or HasLoadedOrAssignedValue is false (but why?)
                    // 2. implementations before change
                    // 3. if previous value not null
                    // 3.1. place parent in temp variable
                    // 3.2. set [Storage].Entity to null
                    // 3.3. remove it from parent list
                    // 4. assign value to [Storage].Entity
                    // 5. if value is not null
                    // 5.1. add it to parent list
                    // 5.2. set FK members with entity keys
                    // 6. else
                    // 6.1. set FK members to defaults (null or 0)
                    // 7. implementationas after change

                    //writer.WriteLine(writer.GetStatement(writer.GetAssignmentExpression(storage, writer.GetPropertySetValueExpression())));
                    var entityMember = writer.GetMemberExpression(parent.Storage, "Entity");
                    // 1.1
                    using (writer.WriteIf(writer.GetDifferentExpression(writer.GetPropertySetValueExpression(),
                                                                        entityMember)))
                    {
                        var otherAssociation = schema.GetReverseAssociation(parent);
                        // 2. code before the change
                        // TODO change interface to require a member instead of a column
                        //foreach (IImplementation implementation in context.Implementations())
                        //    implementation.WritePropertyBeforeSet(writer, ???, context);
                        // 3.
                        using (writer.WriteIf(writer.GetDifferentExpression(entityMember, writer.GetNullExpression())))
                        {
                            var previousEntityRefName = "previous" + parent.Type;
                            // 3.1.
                            writer.WriteLine(writer.GetStatement(
                                writer.GetVariableDeclarationInitialization(parent.Type, previousEntityRefName, entityMember)
                                ));
                            // 3.2.
                            writer.WriteLine(writer.GetStatement(
                                writer.GetAssignmentExpression(entityMember, writer.GetNullExpression())
                                ));
                            // 3.3.
                            writer.WriteLine(writer.GetStatement(
                                writer.GetMethodCallExpression(
                                    writer.GetMemberExpression(writer.GetMemberExpression(previousEntityRefName, otherAssociation.Member), "Remove"),
                                    writer.GetThisExpression())
                                ));
                        }
                        // 4.
                        writer.WriteLine(writer.GetStatement(
                            writer.GetAssignmentExpression(entityMember, writer.GetPropertySetValueExpression())
                            ));

                        // 5. if value is null or not
                        writer.WriteRawIf(writer.GetDifferentExpression(writer.GetPropertySetValueExpression(), writer.GetNullExpression()));
                        // 5.1.
                        writer.WriteLine(writer.GetStatement(
                            writer.GetMethodCallExpression(
                                writer.GetMemberExpression(writer.GetMemberExpression(writer.GetPropertySetValueExpression(), otherAssociation.Member), "Add"),
                                writer.GetThisExpression())
                            ));

                        // 5.2
                        var table = schema.Tables.Single(t => t.Type.Associations.Contains(parent));
                        var childKeys = parent.TheseKeys.ToArray();
                        var childColumns = (from ck in childKeys select table.Type.Columns.Single(c => c.Member == ck))
                                            .ToArray();
                        var parentKeys = parent.OtherKeys.ToArray();

                        for (int keyIndex = 0; keyIndex < parentKeys.Length; keyIndex++)
                        {
                            writer.WriteLine(writer.GetStatement(writer.GetAssignmentExpression(
                                childColumns[keyIndex].Storage ?? childColumns[keyIndex].Member,
                                writer.GetMemberExpression(writer.GetPropertySetValueExpression(), parentKeys[keyIndex])
                                )));
                        }

                        // 6.
                        writer.WriteRawElse();

                        // 6.1.
                        for (int keyIndex = 0; keyIndex < parentKeys.Length; keyIndex++)
                        {
                            var column = table.Type.Columns.Single(c => c.Member == childKeys[keyIndex]);
                            var columnType = System.Type.GetType(column.Type);
                            var columnLiteralType = columnType != null ? writer.GetLiteralType(columnType) : column.Type;
                            writer.WriteLine(writer.GetStatement(writer.GetAssignmentExpression(
                                childColumns[keyIndex].Storage ?? childColumns[keyIndex].Member,
                                column.CanBeNull ? writer.GetNullExpression() : writer.GetNullValueExpression(columnLiteralType)
                                )));
                        }

                        writer.WriteRawEndif();

                        // 7. code after change
                        // TODO change interface to require a member instead of a column
                        //foreach (IImplementation implementation in context.Implementations())
                        //    implementation.WritePropertyAfterSet(writer, ???, context);

                    }
                }
            }
            writer.WriteLine();
        }
예제 #4
0
        void GenerateEntityChildrenAttachment(CodeTypeDeclaration entity, Table table, Database schema)
        {
            var children = GetClassChildren(table).ToList();
            if (!children.Any())
                return;

            var havePrimaryKeys = table.Type.Columns.Any(c => c.IsPrimaryKey);

            var handlers = new List<CodeTypeMember>();

            foreach (var child in children)
            {
                // the reverse child is the association seen from the child
                // we're going to use it...
                var reverseChild = schema.GetReverseAssociation(child);
                // ... to get the parent name
                var memberName = reverseChild.Member;

                var sendPropertyChanging = new CodeExpressionStatement(
                        new CodeMethodInvokeExpression(
                            new CodeMethodReferenceExpression(thisReference, "SendPropertyChanging")));

                var attach = new CodeMemberMethod() {
                    Name = child.Member + "_Attach",
                    Parameters = {
                        new CodeParameterDeclarationExpression(child.Type, "entity"),
                    },
                };
                handlers.Add(attach);
                if (havePrimaryKeys)
                    attach.Statements.Add(sendPropertyChanging);
                attach.Statements.Add(
                        new CodeAssignStatement(
                            new CodePropertyReferenceExpression(new CodeVariableReferenceExpression("entity"), memberName),
                            thisReference));

                var detach = new CodeMemberMethod() {
                    Name = child.Member + "_Detach",
                    Parameters = {
                        new CodeParameterDeclarationExpression(child.Type, "entity"),
                    },
                };
                handlers.Add(detach);
                if (havePrimaryKeys)
                    detach.Statements.Add(sendPropertyChanging);
                detach.Statements.Add(
                        new CodeAssignStatement(
                            new CodePropertyReferenceExpression(new CodeVariableReferenceExpression("entity"), memberName),
                            new CodePrimitiveExpression(null)));
            }

            if (handlers.Count == 0)
                return;

            handlers.First().StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Attachment handlers"));
            handlers.Last().EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, null));
            entity.Members.AddRange(handlers.ToArray());
        }