Search code examples
c#asp.net-mvcentity-frameworkentity-framework-6edmx-designer

How to generate .edmx.diagram file using edmgen.exe?


Using the suggestion provided in GitHub, I was able to generate the EDMX files needed for an ASP.net project. Using a command like:

"%windir%\Microsoft.NET\Framework\v4.0.30319\edmgen.exe" /mode:fullgeneration    /c:"Data Source=%datasourceserver%; Initial Catalog=School; Integrated Security=SSPI"    /project:School /entitycontainer:SchoolEntities /namespace:SchoolModel /language:CSharp

But I don't know how to generate the accompanying edmx.diagram file that gets generated in Visual Studio if we create the EDMX via ADO.Net Data Model addition to existing project.

In the Solution Explorer, the file can be seen in a location like so: enter image description here

The file can also be opened in Visual studio to see the Database structure in the form of a UML diagram like so: enter image description here

Additionally the file generated for this gets shown like so: enter image description here

I read the documentation on how to use edmgen.exe to generate the edmx files as well from the official documentation.

I believe that the documentation to generate the edmx.document file has been missed in the Microsoft documentation and I have been unable to come up with a solution for this by myself. I have been stuck for quite some time on this problem and need help in resolving this.

I have used a similar mechanism to generate files needed in the SQL2LINQ convertor project. Having this capability could help tremendously. Please help me.

Edit 1: I have noticed that the edmx.diagram file has property like so. What I am not sure is if Visual Studio internally uses some other executable to generate the diagram files or if there is an un-documented flag that that can create the diagram files via command line. Please forgive my Edit this information was not avaialable while originally posting the question.

enter image description here

Edit 2: All the steps involved in the process I use:

Step1: Copy my resource files to the folder where I require my edmx and dependency files to be generated.

Note: These files are dummy files and will be generated from the command line command I have pasted in the question.

Step 2: Run the command line command by navigating to the same path.

Step 3: After the command line is run, the connection string collected form the user will help in generating the necessary CSDL, SSDL and MSL files in the same directory. the files are then read and replaced int he edmx files that i have included in the resources folder in the link above.

Step 4: Run The textTransform.bat file to run the texttransform.exe from the Windows SDK path for Texttransform.exe.

Observation: At this stage, 5 of the 6 files are created namely:

  1. .context.tt
  2. .context.cs
  3. .Designer.cs
  4. .tt
  5. .cs

corresponding to the name provided by the user.

But the file .edmx.diagram is missing.

Code that does step 1 through 4:

internal class Globals {
    public static string EDMXworkingDirectory = @"C:\ERachana\EDMX\EDMXFiles\EDMXParts";
    public static bool isEDMXAlreadyGenerated = false;

    public static string Server = "",Database = "", UserName = "",Password = "";
    public static string ProjectName = "", UserDefinedObjectName = "_appdb", TemporaryDirectoryPath="";

    public static string GetSubstringBetweenStrings(string Full, string startMatch, string endMatch) {
        int pFrom = Full.IndexOf(startMatch) + startMatch.Length;
        int pTo = Full.LastIndexOf(endMatch);
        if (pTo > pFrom)
            return Full.Substring(pFrom, pTo - pFrom);
        else
            return "";
    }

    public static void GenerateORMFiles() {
        string workingDirectory = EDMXworkingDirectory;
        if (!isEDMXAlreadyGenerated) {
            // Show Progress Bar here
            try {
                isEDMXAlreadyGenerated = true;
                Directory.CreateDirectory(@"C:\ERachana");
                Directory.CreateDirectory(@"C:\ERachana\EDMX");
                Directory.CreateDirectory(@"C:\ERachana\EDMX\EDMXFiles");
                Directory.CreateDirectory(workingDirectory);

                string CommandToCreateEDMXOnCommandLine = "\"%windir%\\Microsoft.NET\\Framework\\v4.0.30319\\edmgen.exe\" /mode:fullgeneration /c:\"data source = "
                                    + Server + "; initial catalog = "
                                    + Database + "; user id = "
                                    + UserName + "; password = "
                                    + Password + "; MultipleActiveResultSets = True; persist security info = True; App = EntityFramework\" /project:DataModel /entitycontainer:DBContext /namespace:Models /language:CSharp & exit";

                string ResourcesDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + @"\Resources\";
                string EDMXFileName = "DataModel.edmx";
                string ContextFileName = "DataModel.Context.tt";
                string TablesFileName = "DataModel.tt";

                string EdmxLocation = workingDirectory + @"\" + EDMXFileName;
                File.Copy(Path.Combine(ResourcesDirectory, EDMXFileName), EdmxLocation, true);
                File.Copy(Path.Combine(ResourcesDirectory, ContextFileName), workingDirectory + @"\" + ContextFileName, true);
                File.Copy(Path.Combine(ResourcesDirectory, TablesFileName), workingDirectory + @"\" + TablesFileName, true);
                using (var process = new Process()) {
                    var startInfo = new ProcessStartInfo {
                        WorkingDirectory = workingDirectory,
                        WindowStyle = ProcessWindowStyle.Minimized,
                        CreateNoWindow = true,
                        RedirectStandardInput = true,
                        UseShellExecute = false,
                        FileName = "cmd.exe",
                        Verb = "runas"
                    };

                    process.StartInfo = startInfo;
                    process.Start();
                    process.StandardInput.WriteLine(CommandToCreateEDMXOnCommandLine);
                    process.WaitForExit();
                    process.Close();
                    process.Dispose();
                }
                string text = File.ReadAllText(EdmxLocation);

                string c = "";
                c = parseSCMDLFiles(workingDirectory + @"\DataModel.ssdl", "Schema");
                text = text.Replace("###StorageModelsSchema", c);

                c = parseSCMDLFiles(workingDirectory + @"\DataModel.csdl", "Schema");
                text = text.Replace("###ConceptualModelsSchema", c);

                c = parseSCMDLFiles(workingDirectory + @"\DataModel.msl", "Mapping");
                text = text.Replace("###Mappings", c);

                File.WriteAllText(EdmxLocation, text);

                string[] fileToBeDeleted = Directory.GetFiles(workingDirectory);
                foreach (string filePath in fileToBeDeleted) {
                    if (filePath.Contains("DataModel.ObjectLayer.cs") || filePath.Contains("DataModel.Views.cs")) {
                        File.Delete(filePath);
                    } else {
                        if (filePath.ToLower().Contains(".edmx") || filePath.ToLower().Contains(".tt") || filePath.ToLower().Contains(".cs"))
                            continue;
                        File.Delete(filePath);
                    }
                }
                string location = @"C:\ERachana\EDMX";
                string TransformFileName = "transform_all.bat";
                File.Copy(Path.Combine(ResourcesDirectory, TransformFileName), location + @"\" + TransformFileName, true);
                string batFileCommand = "/C " + location + @"\" + TransformFileName;

                using (var process = new Process()) {
                    var startInfo = new ProcessStartInfo() {
                        WorkingDirectory = location,
                        WindowStyle = ProcessWindowStyle.Minimized,
                        CreateNoWindow = true,
                        UseShellExecute = false,
                        FileName = @"cmd.exe",
                        Verb = "runas",
                        Arguments = batFileCommand
                    };

                    process.StartInfo = startInfo;
                    process.Start();
                    process.WaitForExit();
                    process.Close();
                    process.Dispose();
                }
            } catch {
                MessageBox.Show("Only Projects with MSSQL may be converted to Web Projects");
            } finally {
                // Close Progressbar here
            }
        }
    }

    public static string parseSCMDLFiles(string EDMXDirectoryFile, string tag) {
        List<string> lines = File.ReadLines(EDMXDirectoryFile).ToList();
        string content = "";
        bool flagEnable = false;
        foreach (string line in lines) {
            if (line.Contains("</" + tag + ">"))
                flagEnable = false;
            if (flagEnable == true)
                content += line + Environment.NewLine;
            if (line.Contains("<" + tag))
                flagEnable = true;
        }
        return content;
    }
}

Solution

  • Short Answer

    To make the edmx designer show the diagrams, you can use either of the following options:

    • Having <Designers></Designers> tag in edmx file.

    • Having .edmx.designer file with following contents and child of .edmx file:

      <?xml version="1.0" encoding="utf-8"?>
      <edmx:Edmx Version="3.0" xmlns:edmx="http://schemas.microsoft.com/ado/2009/11/edmx">
        <edmx:Designer>
          <edmx:Diagrams>
      
          </edmx:Diagrams>
        </edmx:Designer>
      </edmx:Edmx>
      

    Long Answer

    EdmGen.exe will not generate edmx for you, but it generates all data that you need to create an edmx file yourself. You can simply create edmx file by mixing those csdl, ssdl and msl.

    Also about the diagram file, you should know edmx.diagram file is not necessary. When you create the edmx file, with empty <Diagrams></Diagrams> tag, the first time that you open the edmx file in designer, Visual Studio will create the content for the tag for you. Then if for any reason you like to have ot in separate file, you can simply right click on design surface of the edmx and choose Move Diagrams to Separate File.

    You can follow the following steps to create an edmx file manually (or by code) yourself:

    1- Run EdmGen

    "%windir%\Microsoft.NET\Framework\v4.0.30319\edmgen.exe" /mode:fullgeneration  /c:"Data Source=SERVERNAME; Initial Catalog=DATABASENAME;Integrated Security=SSPI" /project:PROJECT /entitycontainer:CONTAINER /namespace:NAMESPACE /language:CSharp /targetversion:4.5
    

    2- Create an edmx file with following contents.

    Please note that the edmx content which I used in this post, is based on /targetversion:4.5 switch.

    <?xml version="1.0" encoding="utf-8"?>
    <edmx:Edmx Version="3.0" xmlns:edmx="http://schemas.microsoft.com/ado/2009/11/edmx">
      <!-- EF Runtime content -->
      <edmx:Runtime>
        <!-- SSDL content -->
        <edmx:StorageModels>
        $SSDL$
        </edmx:StorageModels>
        <!-- CSDL content -->
        <edmx:ConceptualModels>
        $CSDL$
        </edmx:ConceptualModels>
        <!-- C-S mapping content -->
        <edmx:Mappings>
        $MSL$
        </edmx:Mappings>
      </edmx:Runtime>
      <!-- EF Designer content (DO NOT EDIT MANUALLY BELOW HERE) -->
      <Designer xmlns="http://schemas.microsoft.com/ado/2009/11/edmx">
        <Connection>
          <DesignerInfoPropertySet>
            <DesignerProperty Name="MetadataArtifactProcessing" Value="EmbedInOutputAssembly" />
          </DesignerInfoPropertySet>
        </Connection>
        <Options>
          <DesignerInfoPropertySet>
            <DesignerProperty Name="ValidateOnBuild" Value="true" />
            <DesignerProperty Name="EnablePluralization" Value="true" />
            <DesignerProperty Name="IncludeForeignKeysInModel" Value="true" />
            <DesignerProperty Name="UseLegacyProvider" Value="false" />
            <DesignerProperty Name="CodeGenerationStrategy" Value="None" />
          </DesignerInfoPropertySet>
        </Options>
        <!-- Diagram content (shape and connector positions) -->
        <Diagrams></Diagrams>
      </Designer>
    </edmx:Edmx>
    

    3- Replace the placeholders which you have in edmx with content of the following files (without <?xml version="1.0" encoding="utf-8"?>):

    • $SSDL$ should be replaced with content of the ssdl file.
    • $CSDL$ should be replaced with content of the csdl file.
    • $MSL$ should be replaced with content of the msl file.

    Note

    .edmx.designer is optional and it's enough to have an <Diagrams></Diagrams> tag in edmx like what I shared above, then the first time that you open Visual Studio, the diagram will be created for you automatically. Also for any reason if you like to have diagram i a separate file, you can simply create an empty diagram file, which will be filled by VS at the first time that you open edmx:

    <?xml version="1.0" encoding="utf-8"?>
    <edmx:Edmx Version="3.0" xmlns:edmx="http://schemas.microsoft.com/ado/2009/11/edmx">
      <edmx:Designer>
        <edmx:Diagrams>
    
        </edmx:Diagrams>
      </edmx:Designer>
    </edmx:Edmx>