So I'm trying to deploy a database on Azure using EF code first. I have one model:
public class User
{
[Key]
public int PersonID { get; set; }
[Required(ErrorMessage = "A first name is required.")]
[StringLength(20, MinimumLength = 2, ErrorMessage = "Your firstname needs to be atleast 2 letters long")]
[RegularExpression(#"^[a-zA-Z]*$", ErrorMessage = "Your firstname can only contain letters")]
[Display(Name = "First Name:")]
public string FirstName { get; set; }
}
DataContext-class:
public class DataContext : DbContext
{
public DataContext() : base("DataContext")
{
}
public DbSet<User> User { get; set; }
}
DataContextInitalizer-class:
public class DataContextInitializer : DropCreateDatabaseIfModelChanges<DataContext>
{
}
In the global.asax-file to initalize the datacontext:
Database.SetInitializer(new DataContextInitializer());
And then finally the string to connect to the database in the web.config:
<connectionStrings>
<add name="DataContext" connectionString="Data Source=tcp:*.database.windows.net,1433;Initial Catalog=TestApi20180311012458_db;User ID=usernamehere;Password=passwordhere" providerName="System.Data.SqlClient" />
Thou no tables are created when building the solution. I dont know where I'm missing out. Can you see whats wrong?
Thou no tables are created when building the solution. I dont know where I'm missing out. Can you see whats wrong?
Your code just to connect Azure sql in your local project. And the data initialization just uses to initialize data in table. But your tables have not created yet. If you want to create table in Azure sql, you could use Migrations.
Azure sql connection string in web.config:
<connectionStrings>
<add name="ConnectionStringName" providerName="System.Data.SqlClient" connectionString="Data Source=tcp:[databasename].database.windows.net,1433;Initial Catalog=[databasename];Integrated Security=False;User Id=[username];Password=[password];Encrypt=True;TrustServerCertificate=False;MultipleActiveResultSets=True" />
</connectionStrings>
Open Tools> Nuget Mackage Manager>Package Manager Console. Then enter the following code:
Enable-migrations
Add-migration initial
update-database
After that, you could see the tables are created in Azure Sql.
For another way, you could use publish tool to connect to Azure sql and use Code First Migrations automatically. Do not need to use code to configure manually. Open Publish settings to configure Azure sql. Or you could read this article to learn more details.
Related
I have an MVC application that uses entity framework / code first. I'm trying to set up always encrypted in order to encrypt a column (social security number / SSN). I'm running everything in Azure, including using Azure vault to store keys.
I have two models, SystemUser and Person. SystemUser is essentially an account / login which can administer 1 or more People.
The definitions look a bit like:
public class Person
{
[StringLength(30)]
[Column(TypeName = "varchar")]
public string SSN { get; set; } // Social Security Number
...
[Required, MaxLength(128)]
public string SystemUserID { get; set; }
[ForeignKey("SystemUserID")]
public virtual SystemUser SystemUser { get; set; }
...
}
public class SystemUser
{
...
[ForeignKey("SystemUserID")]
public virtual HashSet<Person> People { get; set; }
...
}
I have a very basic page set up that just looks up a user and prints out their SSN. This works. I then adapted the page to update SSN and this also works. This to me implies that the Always Encrypted configuration and Azure Vault is set up correctly. I've got "Column Encryption Setting=Enabled" in the connection string and I encrypted the column SSN using SSMS (I'm using deterministic).
In my SystemUser class I have the following method as an implementation for Identity:
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<SystemUser> manager)
{
...
if (this.People.Any())
{
...
}
...
}
This is used for user logins. Running the code results in a:
System.Data.Entity.Core.EntityCommandExecutionException: An error
occurred while executing the command definition. See the inner
exception for details. ---> System.Data.SqlClient.SqlException:
Operand type clash: varchar is incompatible with varchar(30) encrypted
with (encryption_type = 'DETERMINISTIC', encryption_algorithm_name =
'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name =
'CEK_Auto11', column_encryption_key_database_name = 'xxx')
collation_name = 'Latin1_General_BIN2'
It seems to fail on the line above "if (this.People.Any())". Putting a break point just before that line reveals the following about this.People:
'((System.Data.Entity.DynamicProxies.SystemUser_9F939A0933F4A8A3724213CF7A287258E76B1C6775B69BD1823C0D0DB6A88360)this).People'
threw an exception of type
'System.Data.Entity.Core.EntityCommandExecutionException' System.Collections.Generic.HashSet
{System.Data.Entity.Core.EntityCommandExecutionException}
Any ideas here? Am I doing something that Always Encrypted does not support?
Always encryption is not having support in entity framework. MS still working.
This Blog Using Always Encrypted with Entity Framework 6 explains how to use Always Encrypted with Entity Framework 6 for DataBase first and Code First From existing database and Code first-Migrations with work arounds for different scenarios and problems.
According to https://blogs.msdn.microsoft.com/sqlsecurity/2015/08/27/using-always-encrypted-with-entity-framework-6/
Pass the constant argument as closure – this will force parametrization, producing >correct query:
var ssn = "123-45-6789";
context.Patients.Where(p => p.SSN == ssn);
I have created a database using EF code-first like there http://blogs.msdn.com/b/adonet/archive/2011/03/15/ef-4-1-code-first-walkthrough.aspx. But when I input data to db by add() and then call savechanges() I don't see new database in SQL Server databases folder and there no exceptions. Is it right? Where can I find my database and how to put it in databases folder?
I work with this code:
public class Name
{
public long NameId { get; set; }
public string FullName { get; set; }
}
public class InfoContext : DbContext
{
public DbSet<Name> Names { get; set; }
}
Then I call it:
var db = new InfoContext();
var Names = new Name
{
NameId = 1,
FullName = "test"
};
db.Names.Add(Name);
db.SaveChanges();
var test = db.Names.Find(1);//there I get correct value
I have connectionString in web.config like this:
<connectionStrings>
<add name="InfoName" providerName="System.Data.SqlClient"
connectionString="Server = .\MYINSTANCE; Initial Catalog=mydbname;" />
</connectionStrings>
Based on your comments you need to modify the web.config file in your project root (not the one in your Views folder. In there you can add a section as follows:
<connectionStrings>
<add name="EFDbContext" connectionString="Data Source = .; Initial Catalog = ITSDB; Integrated Security = true" providerName="System.Data.SqlClient"/>
</connectionStrings>
The name property of the element is the DbContext name of your Data model, so if your class is defined as:
public class SomeContext : DbContext
{
...
}
Then your config should be:
<connectionStrings>
<add name="SomeContext" connectionString="Data Source = .; Initial Catalog = ITSDB; Integrated Security = true" providerName="System.Data.SqlClient"/>
</connectionStrings>
As for the connection string, its dependent on your database.
Check the defaultConnectionFactory type in your config. I expect it is set to LocalConnectionFactory, as this seems to be default.
Change it to the following and your SQL instance will be used.
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework">
<parameters>
<parameter value="Data Source=.; Integrated Security=True; MultipleActiveResultSets=True;" />
</parameters>
</defaultConnectionFactory>
Your DB should appear in SQL Management Studio (SQLMS) with a name that matches the namespace and DbContext.
Or you can just put in "Data Source = " value your server's name which selected in you SQL Management Studio.
<connectionStrings>
<add name="SomeContext" connectionString="Data Source = **Server'sName**; Initial Catalog = ITSDB; Integrated Security = true" providerName="System.Data.SqlClient"/>
I just enabled migrations in my project and added a few fields to UserProfile:
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string Description { get; set;}
public DateTime? CreatedOn { get; set; }
public DateTime? LastAccess { get; set; }
}
I Add-migration AddFieldsForUserProfile and it created:
...
public override void Up()
{
AddColumn("dbo.UserProfile", "Email", c => c.String());
AddColumn("dbo.UserProfile", "Description", c => c.String());
AddColumn("dbo.UserProfile", "CreatedOn", c => c.DateTime());
AddColumn("dbo.UserProfile", "LastAccess", c => c.DateTime());
}
...
Update-database -verbose yielded this output:
Target database is: 'Hifi.Models.HifiContext' (DataSource: (localdb)\v11.0, Provider: System.Data.SqlClient, Origin: Convention).
Applying code-based migrations: [201303311011083_AddFieldsForUserProfile].
Applying code-based migration: 201303311011083_AddFieldsForUserProfile.
ALTER TABLE [dbo].[UserProfile] ADD [Email] [nvarchar](max)
ALTER TABLE [dbo].[UserProfile] ADD [Description] [nvarchar](max)
ALTER TABLE [dbo].[UserProfile] ADD [CreatedOn] [datetime]
ALTER TABLE [dbo].[UserProfile] ADD [LastAccess] [datetime]
[Inserting migration history record]
Running Seed method.
Apparently all went well, but after recieving an error that the coloumn CreatedOn does not exist, I looked into the database with the Server Explorer and indeed, all 4 coloumns are missing in my UserProfile table. What did I do wrong?
Edit
I found my error. Somehow I had two different mdf files aspnet-Hifi-20130330054424.mdf and Hifi.Models.HifiContext.mdf which had the same file size and I assumed both were necessary. My Server Explorer was using the aspnetxx.mdf and the database changes were made to HifiContext.mdf. Shame on me.
On a related note I had trouble correctly displaying a list of all registered users. It was always empty altough I could login flawlessly. Somehow for login aspnetxx.mdf was queried but my MemberListController queried HifiContext.mdf. After changing my connection string I had initially no registered users, new ones were added to HifiContext.mdf and the list worked properly. How did this happen?
are you sure you're looking at the right Db?
it seems so though. Did you get any errors? Any special permissions etc.
My advice is to create a new connection - e.g. config and
<connectionStrings>
<add name="HifiContext" connectionString="Data Source=MACHINE\INSTANCE;Initial Catalog=HiFi;Integrated Security=True; MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
</connectionStrings>`
...and backup your old just in case. i.e. recreate Db from scratch
If nothing works - try recreating if you just turned migrations on - no other ideas.
As for why the out-of-sync happened - hard to say for sure - but I'm guessing you had 'two connection strings' as well (or at some level).
Make sure that you connection string is 'named' the same as your
dbcontext - or put connection at your at DbContext directly
. It is sometimes a problem, as it's not apparent what the EF/CF 'makes' as its default.
call this method in your startup code to have the database recreated with the new fields:
public void CheckForDBChanes()
{
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<Context>());
}
At work we currently have a very large web application with a connection to a massive database. We have been using Entity Framework for a while now and to make things easier we divided the database into many Entity models. This works well for us but we ran into an issue. Each EF model needs its own connection string due to the metadata part of the connection string. Managing so many connection string is a pain.
Now I have a solution that I think will work. I am going to create a class that will have the metadata info saved as a property also concatenated to the standard connection string in the web.config. So when we use the connection string "Database.EntityConnectionString" it will give me the Entity Connection string but we only have to manage a single connection string in the web.config. We will still have to manage the class with the metadata but Models don't change very much and we don't create them often so maintenance should be fine. My question, is there a better way of dealing with this issue or how would you do it?
Thanks!
This is how I have implemented my solution to this problem:
namespace DBLibrary
{
public enum Models
{
Model1,
Model2
}
public static class Database
{
public static string EntitiesConnectionString(Models model)
{
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(ConfigurationManager.ConnectionStrings["Default"].ConnectionString);
builder["MultipleActiveResultSets"] = true;
builder["Connect Timeout"] = 30;
EntityConnectionStringBuilder entityBuilder = new EntityConnectionStringBuilder();
entityBuilder.Provider = "System.Data.SqlClient";
entityBuilder.ProviderConnectionString = builder.ConnectionString;
switch (model)
{
case Models.Model1:
entityBuilder.Metadata = "res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl";
return entityBuilder.ToString();
case Models.Model2:
entityBuilder.Metadata = "res://*/Model2.csdl|res://*/Model2.ssdl|res://*/Model2.msl";
return entityBuilder.ToString();
default:
throw new Exception("Invalid model, no connection string defined");
}
}
}
}
I still need to clean up the code and all but I think this give you a good idea on how this can be implemented. I would still be very interested if there are different and better ways of doing this.
Thanks!
Add Default Construction in your Class
public class ItemContext : DbContext
{
public DbSet<Item>Items get; set; }
public DbSet<ItemDetail> ItemDetails { get; set; }
public ItemContext ()
{
this.Database.Connection.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
}
}
I had the same problem. I have solved it by following way:
I have created two edmx file, but while creating second edmx file, i ignored the connection string to be save in config file. This way my config file will hold only one Connection string.
Then i modified following lines in my connection string:
<add name="MyDbContext" connectionString="metadata=res://*/;provider=System.Data.SqlClient;provider connection string="data source=abc;initial catalog=mydb;persist security info=True;user id=myuser;password=password;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
Just replace "res://model1.csdl" with "res://*/" and it works like a charm.
You can specify this connection name in constructor of your dbcontext class like:
public MyDbContext() : base("name=NameOfYourConnectionString") // Name of your connection string
{ }
Note: I am using Entity Framework 5.0.
I am trying to incorporate 'EF Tracing Data Provider' into an existing MVC2 app using VS2010, .NET 4.0 in order to log all SQL commands. I have no interest at this time in the caching provider. I beleive I have followed all the steps listed in the blog posting. BLOG POST My project does compile without error, however when I attempt to run the project I get the following error:
'String cannot have zero length.' The error points to Extended_JCIMS_MVC2_EF_Entities.cs Line: 25
Line 25: public ExtendedJCIMS_DevEntities(string connectionString)
Line 26: :base(EntityConnectionWrapperUtils.CreateEntityConnectionWithWrappers(
I am unable to determine what is causing this error. I assume the error is referring to the connection string from the Web.Config file. It does not like the 'connectionString' variable. I'm obviously doing something worng. I would appreciate a push in the right direction.
The relevant bits are as follows:
Web.config
--------------------------------------------------------------------------
<add name="JCIMS_DevEntities"
connectionString="metadata=res://*/;provider=System.Data.SqlClient;provider connection string="Data Source=MyServer;Initial Catalog=MyDatabase;User ID=MyUser;Password=myPassWord;MultipleActiveResultSets=True""
providerName="System.Data.EntityClient"/>
<system.data>
<DbProviderFactories>
<add name="EF Tracing Data Provider" invariant="EFTracingProvider" description="Tracing Provider Wrapper"
type="EFTracingProvider.EFTracingProviderFactory, EFTracingProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=def642f226e0e59b" />
<add name="EF Generic Provider Wrapper" invariant="EFProviderWrapper" description="Generic Provider Wrapper"
type="EFProviderWrapperToolkit.EFProviderWrapperFactory, EFProviderWrapperToolkit, Version=1.0.0.0, Culture=neutral, PublicKeyToken=def642f226e0e59b" />
</DbProviderFactories>
</system.data>
Global.ascx
-----------------------------------------------------------------------
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
//EFTracingProviderConfiguration - LOG ALL Sql commands
EFTracingProviderConfiguration.LogToFile = Server.MapPath("~/JCIMS_MVC2_EF_SQL_Logfie.txt");
}
Extended_JCIMS_MVC2_EF_Entities.cs
--------------------------------------------------------------------------
namespace JCIMS_MVC2_EF.DomainModel
{
/// <summary>
/// Partial calss that Extends the EF Datacontext Class
/// </summary>
public partial class ExtendedJCIMS_DevEntities : JCIMS_DevEntities
{
private TextWriter logOutput;
public ExtendedJCIMS_DevEntities()
: this("name=JCIMS_DevEntities")
{
}
public ExtendedJCIMS_DevEntities(string connectionString)
: base(EntityConnectionWrapperUtils.CreateEntityConnectionWithWrappers(
connectionString,
"EFTracingProvider"
))
{
}
//... and more
}
}
SearchRepository.cs
------------------------------------------------------------------
public class SQLSearchRepository : ISearchRepository
{
//Database connection
private ExtendedJCIMS_DevEntities db = new ExtendedJCIMS_DevEntities(); // tracing version
public IEnumerable<SearchResults> ListAll(string strSearch, string chkSearch)
{
return (from s in db.Schools....
// and more...
}
Appreciate any assistance anyone can give me...
Have you debugged and confirmed that the connectionString passed into the ExtendedJCIMS_DevEntities method is not null or empty? That's what the error seems to indicate.