Exemple #1
0
      void WriteConstructorComments(ModelClass modelClass)
      {
         foreach (ModelAttribute requiredAttribute in modelClass.AllRequiredAttributes.Where(x => (!x.IsIdentity || x.IdentityType == IdentityType.Manual)
                                                                                                && !x.IsConcurrencyToken
                                                                                                && x.SetterVisibility == SetterAccessModifier.Public))
            Output($@"/// <param name=""{requiredAttribute.Name.ToLower()}"">{SecurityElement.Escape(requiredAttribute.Summary)}</param>");

         // TODO: Add comment if available
         foreach (NavigationProperty requiredNavigationProperty in modelClass.AllRequiredNavigationProperties()
                                                                              .Where(np => np.AssociationObject.SourceMultiplicity != Sawczyn.EFDesigner.EFModel.Multiplicity.One
                                                                                       || np.AssociationObject.TargetMultiplicity != Sawczyn.EFDesigner.EFModel.Multiplicity.One))
            Output($@"/// <param name=""{requiredNavigationProperty.PropertyName.ToLower()}""></param>");
      }
Exemple #2
0
      List<string> GetRequiredParameters(ModelClass modelClass, bool? haveDefaults, bool? publicOnly = null)
      {
         List<string> requiredParameters = new List<string>();

         if (haveDefaults != true)
         {
            requiredParameters.AddRange(modelClass.AllRequiredAttributes
                                                   .Where(x => (!x.IsIdentity || x.IdentityType == IdentityType.Manual)
                                                            && !x.IsConcurrencyToken
                                                            && (x.SetterVisibility == SetterAccessModifier.Public || publicOnly != false)
                                                            && string.IsNullOrEmpty(x.InitialValue))
                                                   .Select(x => $"{x.FQPrimitiveType} {x.Name.ToLower()}"));

            // don't use 1..1 associations in constructor parameters. Becomes a Catch-22 scenario.
            requiredParameters.AddRange(modelClass.AllRequiredNavigationProperties()
                                                   .Where(np => np.AssociationObject.SourceMultiplicity != Sawczyn.EFDesigner.EFModel.Multiplicity.One
                                                            || np.AssociationObject.TargetMultiplicity != Sawczyn.EFDesigner.EFModel.Multiplicity.One)
                                                   .Select(x => $"{x.ClassType.FullName} {x.PropertyName.ToLower()}"));
         }

         if (haveDefaults != false)
         {
            requiredParameters.AddRange(modelClass.AllRequiredAttributes
                                                   .Where(x => (!x.IsIdentity || x.IdentityType == IdentityType.Manual)
                                                            && !x.IsConcurrencyToken
                                                            && (x.SetterVisibility == SetterAccessModifier.Public || publicOnly != false)
                                                            && !string.IsNullOrEmpty(x.InitialValue))
                                                   .Select(x =>
                                                            {
                                                               string quote = x.PrimitiveType == "string"
                                                                           ? "\""
                                                                           : x.PrimitiveType == "char"
                                                                              ? "'"
                                                                              : string.Empty;

                                                               string value = FullyQualified(modelClass.ModelRoot, quote.Length > 0
                                                                                                                         ? x.InitialValue.Trim(quote[0])
                                                                                                                         : x.InitialValue);

                                                               return $"{x.FQPrimitiveType} {x.Name.ToLower()} = {quote}{value}{quote}";
                                                            }));
         }

         return requiredParameters;
      }
Exemple #3
0
      List<string> GetRequiredParameterNames(ModelClass modelClass, bool? publicOnly = null)
      {
         List<string> requiredParameterNames = modelClass.AllRequiredAttributes
                                                   .Where(x => (!x.IsIdentity || x.IdentityType == IdentityType.Manual)
                                                            && !x.IsConcurrencyToken
                                                            && (x.SetterVisibility == SetterAccessModifier.Public || publicOnly != false)
                                                            && string.IsNullOrEmpty(x.InitialValue))
                                                   .Select(x => x.Name.ToLower())
                                                   .ToList();

         requiredParameterNames.AddRange(modelClass.AllRequiredNavigationProperties()
                                                   .Where(np => np.AssociationObject.SourceMultiplicity != Sawczyn.EFDesigner.EFModel.Multiplicity.One
                                                               || np.AssociationObject.TargetMultiplicity != Sawczyn.EFDesigner.EFModel.Multiplicity.One)
                                                   .Select(x => x.PropertyName.ToLower()));

         requiredParameterNames.AddRange(modelClass.AllRequiredAttributes
                                                   .Where(x => (!x.IsIdentity || x.IdentityType == IdentityType.Manual)
                                                            && !x.IsConcurrencyToken
                                                            && (x.SetterVisibility == SetterAccessModifier.Public || publicOnly != false)
                                                            && !string.IsNullOrEmpty(x.InitialValue))
                                                   .Select(x => x.Name.ToLower()));

         return requiredParameterNames;
      }
Exemple #4
0
      void WriteConstructor(ModelClass modelClass)
      {
         Output("partial void Init();");
         NL();

         /***********************************************************************/
         // Default constructor
         /***********************************************************************/

         bool hasRequiredParameters = GetRequiredParameters(modelClass, false).Any();

         bool hasOneToOneAssociations = modelClass.AllRequiredNavigationProperties()
                                             .Any(np => np.AssociationObject.SourceMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.One
                                                      && np.AssociationObject.TargetMultiplicity != Sawczyn.EFDesigner.EFModel.Multiplicity.One);

         string visibility = (hasRequiredParameters || modelClass.IsAbstract) && !modelClass.IsDependentType
                           ? "protected"
                           : "public";

         if (visibility == "public")
         {
            Output("/// <summary>");
            Output("/// Default constructor");
            Output("/// </summary>");
         }
         else if (modelClass.IsAbstract)
         {
            Output("/// <summary>");
            Output("/// Default constructor. Protected due to being abstract.");
            Output("/// </summary>");
         }
         else if (hasRequiredParameters)
         {
            Output("/// <summary>");
            Output("/// Default constructor. Protected due to required properties, but present because EF needs it.");
            Output("/// </summary>");
         }

         List<string> remarks = new List<string>();

         if (hasOneToOneAssociations)
         {
            List<Association> oneToOneAssociations = modelClass.AllRequiredNavigationProperties()
                                                         .Where(np => np.AssociationObject.SourceMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.One
                                                                     && np.AssociationObject.TargetMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.One)
                                                         .Select(np => np.AssociationObject)
                                                         .ToList();

            List<ModelClass> otherEndsOneToOne = oneToOneAssociations.Where(a => a.Source != modelClass).Select(a => a.Target)
                                                               .Union(oneToOneAssociations.Where(a => a.Target != modelClass).Select(a => a.Source))
                                                               .ToList();

            if (oneToOneAssociations.Any(a => a.Source.Name == modelClass.Name && a.Target.Name == modelClass.Name))
               otherEndsOneToOne.Add(modelClass);

            if (otherEndsOneToOne.Any())
            {
               string nameList = otherEndsOneToOne.Count == 1
                              ? otherEndsOneToOne.First().Name
                              : string.Join(", ", otherEndsOneToOne.Take(otherEndsOneToOne.Count - 1).Select(c => c.Name))
                              + " and "
                              + (otherEndsOneToOne.Last().Name != modelClass.Name
                                    ? otherEndsOneToOne.Last().Name
                                    : "itself");

               remarks.Add($"// NOTE: This class has one-to-one associations with {nameList}.");
               remarks.Add("// One-to-one associations are not validated in constructors since this causes a scenario where each one must be constructed before the other.");
            }
         }

         Output(modelClass.Superclass != null
                     ? $"{visibility} {modelClass.Name}(): base()"
                     : $"{visibility} {modelClass.Name}()");

         Output("{");

         if (remarks.Count > 0)
         {
            foreach (string remark in remarks)
               Output(remark);

            NL();
         }

         WriteDefaultConstructorBody(modelClass);

         Output("}");
         NL();

         if (visibility != "public" && !modelClass.IsAbstract)
         {
            Output("/// <summary>");
            Output("/// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving.");
            Output("/// </summary>");
            Output($"public static {modelClass.Name} Create{modelClass.Name}Unsafe()");
            Output("{");
            Output($"return new {modelClass.Name}();");
            Output("}");
            NL();
         }

         /***********************************************************************/
         // Constructor with required parameters (if necessary)
         /***********************************************************************/

         if (hasRequiredParameters)
         {
            visibility = modelClass.IsAbstract
                              ? "protected"
                              : "public";

            Output("/// <summary>");
            Output("/// Public constructor with required data");
            Output("/// </summary>");

            WriteConstructorComments(modelClass);
            Output($"{visibility} {modelClass.Name}({string.Join(", ", GetRequiredParameters(modelClass, null))})");
            Output("{");

            if (remarks.Count > 0)
            {
               foreach (string remark in remarks)
                  Output(remark);

               NL();
            }

            foreach (ModelAttribute requiredAttribute in modelClass.AllRequiredAttributes
                                                                     .Where(x => (!x.IsIdentity || x.IdentityType == IdentityType.Manual)
                                                                              && !x.IsConcurrencyToken
                                                                              && x.SetterVisibility == SetterAccessModifier.Public))
            {
               if (requiredAttribute.Type == "String")
                  Output($"if (string.IsNullOrEmpty({requiredAttribute.Name.ToLower()})) throw new ArgumentNullException(nameof({requiredAttribute.Name.ToLower()}));");
               else if (requiredAttribute.Type.StartsWith("Geo"))
                  Output($"if ({requiredAttribute.Name.ToLower()} == null) throw new ArgumentNullException(nameof({requiredAttribute.Name.ToLower()}));");

               Output($"this.{requiredAttribute.Name} = {requiredAttribute.Name.ToLower()};");
               NL();
            }

            foreach (ModelAttribute modelAttribute in modelClass.Attributes.Where(x => x.SetterVisibility == SetterAccessModifier.Public
                                                                                    && !x.Required
                                                                                    && !string.IsNullOrEmpty(x.InitialValue)
                                                                                    && x.InitialValue != "null"))
            {
               string quote = modelAttribute.Type == "String"
                                    ? "\""
                                    : modelAttribute.Type == "Char"
                                          ? "'"
                                          : string.Empty;

               Output(quote.Length > 0
                            ? $"this.{modelAttribute.Name} = {quote}{FullyQualified(modelClass.ModelRoot, modelAttribute.InitialValue.Trim(quote[0]))}{quote};"
                            : $"this.{modelAttribute.Name} = {quote}{FullyQualified(modelClass.ModelRoot, modelAttribute.InitialValue)}{quote};");
            }

            foreach (NavigationProperty requiredNavigationProperty in modelClass.AllRequiredNavigationProperties()
                                                                                 .Where(np => np.AssociationObject.SourceMultiplicity != Sawczyn.EFDesigner.EFModel.Multiplicity.One
                                                                                          || np.AssociationObject.TargetMultiplicity != Sawczyn.EFDesigner.EFModel.Multiplicity.One))
            {
               string parameterName = requiredNavigationProperty.PropertyName.ToLower();
               Output($"if ({parameterName} == null) throw new ArgumentNullException(nameof({parameterName}));");

               if (requiredNavigationProperty.IsCollection)
                  Output($"{requiredNavigationProperty.PropertyName}.Add({parameterName});");
               else if (requiredNavigationProperty.ConstructorParameterOnly)
               {
                  UnidirectionalAssociation association = requiredNavigationProperty.AssociationObject as UnidirectionalAssociation;

                  Output(association.TargetMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany
                              ? $"{requiredNavigationProperty.PropertyName}.{association.TargetPropertyName}.Add(this);"
                              : $"{requiredNavigationProperty.PropertyName}.{association.TargetPropertyName} = this;");
               }
               else
                  Output($"this.{requiredNavigationProperty.PropertyName} = {parameterName};");

               NL();
            }

            foreach (NavigationProperty navigationProperty in modelClass.LocalNavigationProperties()
                                                                        .Where(x => x.AssociationObject.Persistent && (x.IsCollection || x.ClassType.IsDependentType) && !x.ConstructorParameterOnly))
            {
               if (!navigationProperty.IsCollection)
                  Output($"this.{navigationProperty.PropertyName} = new {navigationProperty.ClassType.FullName}();");
               else
               {
                  string collectionType = GetFullContainerName(navigationProperty.AssociationObject.CollectionClass, navigationProperty.ClassType.FullName);
                  Output($"this.{navigationProperty.PropertyName} = new {collectionType}();");
               }
            }

            NL();
            Output("Init();");
            Output("}");
            NL();

            if (!modelClass.IsAbstract)
            {
               Output("/// <summary>");
               Output("/// Static create function (for use in LINQ queries, etc.)");
               Output("/// </summary>");
               WriteConstructorComments(modelClass);

               string newToken = string.Empty;
               List<string> requiredParameters = GetRequiredParameters(modelClass, null);

               if (!AllSuperclassesAreNullOrAbstract(modelClass))
               {
                  List<string> superclassRequiredParameters = GetRequiredParameters(modelClass.Superclass, null);

                  if (!requiredParameters.Except(superclassRequiredParameters).Any())
                     newToken = "new ";
               }

               Output($"public static {newToken}{modelClass.Name} Create({string.Join(", ", GetRequiredParameters(modelClass, null))})");
               Output("{");
               Output($"return new {modelClass.Name}({string.Join(", ", GetRequiredParameterNames(modelClass))});");
               Output("}");
               NL();
            }
         }
      }