对 master 数据库的查询在数据库优先中抛出 UnintentionalCodeFirstException

query on master database throws UnintentionalCodeFirstException in DatabaseFirst

为 sql 服务器主数据库创建模型时遇到巨大问题。 我首先选择了数据库,没有包含任何对象,所以我有一个空模型:

masterModel.cs:

*//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated from a template.
//
//     Manual changes to this file may cause unexpected behavior in your application.
//     Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------*

masterEntities.cs:

  public partial class masterEntities
  {

    static masterEntities()
    {
      // don't let EF modify the database schema...
      Database.SetInitializer<masterEntities>(null);
    }

    public masterEntities(string connectionString)
        : base(connectionString)
    {

    }
}

目标是对 master 数据库发起查询以查明当前用户是否具有 serveradmin 权限(稍后创建新数据库):

   public bool UserHasAdminPrivilegesAtDatabaseServer(DatabaseServer databaseServer)
    {

      var sqlBuilder = new SqlConnectionStringBuilder
      {
        DataSource = databaseServer.Server,
        InitialCatalog = "master",
        PersistSecurityInfo = true,
        IntegratedSecurity = true,
        MultipleActiveResultSets = false,


      };

      //assumes a connectionString name in .config of MyDbEntities
      var entityConnectionStringBuilder = new EntityConnectionStringBuilder
      {
        Provider = "System.Data.SqlClient",
        ProviderConnectionString = sqlBuilder.ConnectionString,
        Metadata = "res://*/masterModel.csdl|res://*/masterModel.ssdl|res://*/masterModel.msl",

      };

      var connstring = entityConnectionStringBuilder.ProviderConnectionString;

      using (var context = new masterEntities(connstring))
      {
        const string sql = "SELECT IS_SRVROLEMEMBER('sysadmin')";//"SELECT IS_SRVROLEMEMBER('sysadmin')";

        var a = context.Database.SqlQuery<int>(sql).FirstOrDefault();
        return a == 1;

      }
    }

现在的问题是,EF 触发了事件 OnModelCreating,该事件在 DatabaseFirst 模式下实现如下:

    using System;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;

    public partial class masterEntities : DbContext
    {
        public masterEntities()
            : base("name=masterEntities")
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            throw new UnintentionalCodeFirstException();
        }

    }

我们在这里:抛出新的 UnintentionalCodeFirstException(); 不知何故,EF 想在 master-db 中创建一些东西;即使我们设置全局静态 属性,它也不应该并且模型本身是空的:Database.SetInitializer<masterEntities>(null)

在这里找到答案:

必须正确填写元数据:

    private static string GetConnectionString(string model, string providerConnectionString)
{

  var efConnection = new EntityConnectionStringBuilder();
  // or the config file based connection without provider connection string
  // var efConnection = new EntityConnectionStringBuilder(@"metadata=res://*/model1.csdl|res://*/model1.ssdl|res://*/model1.msl;provider=System.Data.SqlClient;");
  efConnection.Provider = "System.Data.SqlClient";
  efConnection.ProviderConnectionString = providerConnectionString;
  // based on whether you choose to supply the app.config connection string to the constructor
  efConnection.Metadata = string.Format("res://*/correctModel.{0}.csdl|res://*/correctModel.{0}.ssdl|res://*/correctModel.{0}.msl", model);
  // Make sure the "res://*/..." matches what's already in your config file.
  return efConnection.ToString();
}

解释(归功于reckface)

The exception you get is because when you pass a pure SQL connection string, it assumes you are working with Code first, so it calls the OnModelCreation event. When you include the MetaData section as shown above, that tells EF it's a complete EF connection string.