Entity Framework 从数据库生成模型丢失数据库文档不完美解决方案

Entity Framework 从数据库导入模型时,导入工具生成的EDMX文件是不带有数据库建表时填写的 MS_Description 属性的,今天急用,东拼西凑了几句代码。

<#@ assembly name="System.Core" #>
<#@ assembly name="System.Data" #>
<#@ assembly name="System.Xml" #>
<#@ assembly name="System.Xml.Linq" #>
<#@ assembly name="System.Data.Entity" #>
<#@ assembly name="System.Data.Entity.Design" #>
<#@ assembly name="$(DevEnvDir)Microsoft.Data.Entity.Design.DatabaseGeneration.dll"#>
<#@ assembly name="EnvDTE" #>
<#@ assembly name="System.Configuration" #>
<#@ assembly name="System.Windows.Forms" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Xml.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#@ import namespace="System.Data" #>
<#@ import namespace="System.Data.Common" #>
<#@ import namespace="System.Data.SqlClient" #>
<#@ import namespace="System.Data.EntityClient" #>
<#@ import namespace="System.Data.Entity.Design" #>
<#@ import namespace="System.Data.Metadata.Edm" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Globalization" #>
<#@ import namespace="System.Configuration" #>
<#@ import namespace="System.Runtime.Remoting.Messaging" #>
<#@ import namespace="System.Windows.Forms" #>
<#@ import namespace="Microsoft.Data.Entity.Design.DatabaseGeneration" #>
<#@ include file="EF.Utility.CS.ttinclude"#>
<#@ template language="C#" debug="true" hostspecific="true" #>
<#@ output extension = ".txt" #><#

//修改为要修正的edmx文件
var inputFile = @"Models.edmx";









var loader = new MetadataLoader(this);
var region = new CodeRegion(this);

var ItemCollection = loader.CreateEdmItemCollection(inputFile);
EntityContainer container = ItemCollection.GetItems<EntityContainer>().FirstOrDefault();

//项目路径
string CurrProjectPath =  GetProjectPath();

//连接名称=容器名称
string CurrConnectionStringName = container==null?string.Empty:container.Name ;
string CurrConnectionString = string.Empty;
string CurrProviderName= string.Empty;

CurrConnectionString = GetConnectionString(ref CurrConnectionStringName,out CurrProviderName);

//EntityClientConnectionString转SqlClientConnectionString
if(CurrConnectionString.StartsWith("meta"))
{
    EntityConnectionStringBuilder scsb= new EntityConnectionStringBuilder(CurrConnectionString);
    CurrConnectionString = scsb.ProviderConnectionString;
    CurrProviderName = scsb.Provider;
}


using(FixEDMXDoc fixEDMXDoc = new FixEDMXDoc(CurrConnectionString,CurrProjectPath + "\\" + inputFile,CurrProjectPath + "\\" + inputFile))
{
	fixEDMXDoc.CreateDocumentation();
}
#><#+
public EnvDTE.Project GetCurrentProject()  {

    IServiceProvider _ServiceProvider = (IServiceProvider)Host;
    if (_ServiceProvider == null)
        throw new Exception("Host property returned unexpected value (null)");
	
    EnvDTE.DTE dte = (EnvDTE.DTE)_ServiceProvider.GetService(typeof(EnvDTE.DTE));
    if (dte == null)
        throw new Exception("Unable to retrieve EnvDTE.DTE");
	
    Array activeSolutionProjects = (Array)dte.ActiveSolutionProjects;
    if (activeSolutionProjects == null)
        throw new Exception("DTE.ActiveSolutionProjects returned null");
	
    EnvDTE.Project dteProject = (EnvDTE.Project)activeSolutionProjects.GetValue(0);
    if (dteProject == null)
        throw new Exception("DTE.ActiveSolutionProjects[0] returned null");
	
    return dteProject;

}

private string GetProjectPath()
{
    EnvDTE.Project project = GetCurrentProject();
    System.IO.FileInfo info = new System.IO.FileInfo(project.FullName);
    return info.Directory.FullName;
}

private string GetConfigPath()
{
    EnvDTE.Project project = GetCurrentProject();
    foreach (EnvDTE.ProjectItem item in project.ProjectItems)
    {
        // if it is the app.config file, then open it up
        if (item.Name.Equals("App.config",StringComparison.InvariantCultureIgnoreCase) || item.Name.Equals("Web.config",StringComparison.InvariantCultureIgnoreCase))
			return GetProjectPath() + "\\" + item.Name;
    }
    return String.Empty;
}
string GetConnectionString(ref string connectionStringName, out string providerName)
{
    var _CurrentProject = GetCurrentProject();

	providerName=null;
    
    string result="";
    ExeConfigurationFileMap configFile = new ExeConfigurationFileMap();
    configFile.ExeConfigFilename = GetConfigPath();

    if (string.IsNullOrEmpty(configFile.ExeConfigFilename))
        throw new ArgumentNullException("The project does not contain App.config or Web.config file.");
    
    
    var config = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(configFile, ConfigurationUserLevel.None);
    var connSection=config.ConnectionStrings;

    //if the connectionString is empty - which is the defauls
    //look for count-1 - this is the last connection string
    //and takes into account AppServices and LocalSqlServer
    if(string.IsNullOrEmpty(connectionStringName))
    {
        if(connSection.ConnectionStrings.Count>1)
        {
			connectionStringName = connSection.ConnectionStrings[connSection.ConnectionStrings.Count-1].Name;
            result=connSection.ConnectionStrings[connSection.ConnectionStrings.Count-1].ConnectionString;
            providerName=connSection.ConnectionStrings[connSection.ConnectionStrings.Count-1].ProviderName;
        }            
    }
    else
    {
        try
        {
            result=connSection.ConnectionStrings[connectionStringName].ConnectionString;
            providerName=connSection.ConnectionStrings[connectionStringName].ProviderName;
        }
        catch
        {
            result="There is no connection string name called '"+connectionStringName+"'";
        }
    }
	if (String.IsNullOrEmpty(providerName))
		providerName="System.Data.SqlClient";
    return result;
}

//Copy From http://eftsqldocgenerator.codeplex.com/
class FixEDMXDoc : IDisposable
{
    public String ConnectionString { get; set; }
    public String InputFileName { get; set; }
    public String OutputFileName { get; set; }

    private SqlConnection _connection;


    public FixEDMXDoc(String connectionString, String inputFileName, String outputFileName)
    {
        this.ConnectionString = connectionString;
        this.InputFileName = inputFileName;
        this.OutputFileName = outputFileName;

        
        this._connection = new SqlConnection(connectionString);
        this._connection.Open();
    }
    public void Dispose()
    {
        this._connection.Dispose();
    }

    public void CreateDocumentation()
    {

        XDocument doc = XDocument.Load(this.InputFileName);
        IEnumerable<XElement> entityTypeElements = doc.Descendants("{http://schemas.microsoft.com/ado/2008/09/edm}EntityType");
		
        foreach (XElement entityTypeElement in entityTypeElements)
        {
            String tableName = entityTypeElement.Attribute("Name").Value;
            IEnumerable<XElement> propertyElements = entityTypeElement.Descendants("{http://schemas.microsoft.com/ado/2008/09/edm}Property");



            this.AddNodeDocumentation(entityTypeElement, GetTableDocumentation(tableName));

            foreach (XElement propertyElement in propertyElements)
            {
                String columnName = propertyElement.Attribute("Name").Value;
                this.AddNodeDocumentation(propertyElement, GetColumnDocumentation(tableName, columnName));
            }
        }

        Console.WriteLine("Writing result to {0}", this.OutputFileName);
        if (File.Exists(this.OutputFileName))
            File.Delete(this.OutputFileName);
        doc.Save(this.OutputFileName);
    }
    private void AddNodeDocumentation(XElement element, String documentation)
    {
        if (String.IsNullOrEmpty(documentation))
            return;
        element.Descendants("{http://schemas.microsoft.com/ado/2008/09/edm}Documentation").Remove();

        element.AddFirst(new XElement("{http://schemas.microsoft.com/ado/2008/09/edm}Documentation", new XElement("{http://schemas.microsoft.com/ado/2008/09/edm}Summary", documentation)));
    }
    private String GetTableDocumentation(String tableName)
    {
        using (SqlCommand command = new SqlCommand(@" SELECT [value] 
                                                      FROM fn_listextendedproperty (
                                                            'MS_Description', 
                                                            'schema', 'dbo', 
                                                            'table',  @TableName, 
                                                            null, null)", this._connection))
        {

            command.Parameters.AddWithValue("TableName", tableName);

            return command.ExecuteScalar() as String;
        }
    }
    private String GetColumnDocumentation(String tableName, String columnName)
    {
        using (SqlCommand command = new SqlCommand(@"SELECT [value] 
                                                     FROM fn_listextendedproperty (
                                                            'MS_Description', 
                                                            'schema', 'dbo', 
                                                            'table', @TableName, 
                                                            'column', @columnName)", this._connection))
        {

            command.Parameters.AddWithValue("TableName", tableName);
            command.Parameters.AddWithValue("ColumnName", columnName);

            return command.ExecuteScalar() as String;
        }
    }
}
#>

  把上面的代码保存为[.tt]类型的文件,并加入项目,修改 [var inputFile = @"Models.edmx";]这句的 Models.edmx为要添加文档的edmx文件,然后保存。

实体模型更改后,要重新写入文档,这时在 这个[.tt]文件上点右键,选择“运行自定义工具”。

posted @ 2012-01-13 13:42  BinSys  阅读(881)  评论(0编辑  收藏  举报