How to use Membership provider with EF Code First?
I have models based on EF Code First an开发者_开发知识库d I want to use them with the default MembershipProvider, but I don't know how to write the model correctly, so it won't erase all my data on recreating the tables when there were changes made to the model.
Have a look at this project
http://codefirstmembership.codeplex.com/
It has entity classes for users and roles, as well as a roleprovider and membershipprovider implementation. If you include the users and roles in your datacontext class the tables will be created in your database.
Your question has two parts.
- How to use asp.net membership API with EF code first?
- How to preserve existing data when model changes?
as for How to preserve existing data when model changes, as far as with EF 4.0/ asp.net mvc 3, database migrations are not yet supported. You will have to move to asp.net mvc 4.0/ EF 4.3 where database migrations are supported or use similar alternatives , but its still beta release.
asp.net mvc 4.0 database migration in scott gu's blog
Now coming to the point on how to use asp.net membership provider with EF code first. There are couple of challenges :
We cannot/should not do an join with asp.net membership provider tables. Its not recommended, so my suggestion will be to create a "adapter class" for asp.net membership provider classes. For ex :
public class UserAdapter { // all user related attributes. Not stored in membership schema, but your schema public string UserProxyName; // some attributes stored in membership schema [NotMapped] public string Email { get { Membership.GetUser(UserProxyName).Email; } } // some attributes stored in membership schema and not in your schema [NotMapped] public string[] UserRoles { get { return Roles.GetRolesForUser(UserProxyName); } } }
Now for updating information , you may write some functions in Model itself, however i would suggest create a UserRepository with repository design pattern to handle user CRUD operations.
Second challenge is how to create the database on first run. As seeding becomes an issue, if you want to seed user information then seperately running aspnet_regsql is not efficient as membership schema is expected before the seeding happens. I came across this nice article , with some fine tuning it worked for me :
asp.net membership and EF
Currently (EF 4.1 CTP) EF Code First doesn't have that option. It always drops a table if you made changes to model.
Update:
EF 4.1 RTM allows you to create a custom database initializer and specify creation of db objects and data seeding.
If you are using SQL Server, then check this :
http://www.paragm.com/ef-v4-1-code-first-and-asp-net-membership-service/
There is also my library which basically allows you to define how almost everything should be configured including: key type, where the your context object is, and where your user/role entities are located. Extendable using abstract base classes or interfaces. Also works quite well out of the box with repository pattern / unit of work / IoC Containers.
Source: https://github.com/holyprin/holyprin.web.security
NuGet: https://nuget.org/packages/Holyprin.Web.Security
In my DbContext.cs file I have a Seed function where I call the ApplicationServices.InstallServices()
to install the ASP.NET Membership to my database. Now everytime my initializer drop the database it recreates ASP.NET Membership schema again.
public class PanelInitializer : DropCreateDatabaseAlways<PanelContext>
{
protected override void Seed(PanelContext context)
{
//Install ASP.NET Membership
ApplicationServices.InstallServices(SqlFeatures.Membership | SqlFeatures.RoleManager);
new List<Panel>
{
The ApplicationServices class
using System.Configuration;
using System.Data.SqlClient;
using System.Web.Management;
namespace Lansw.Panels.DataAccess.Contexts
{
public class ApplicationServices
{
readonly static string DefaultConnectionString = ConfigurationManager.AppSettings["DefaultConnectionString"];
readonly static string ConnectionString = ConfigurationManager.ConnectionStrings[DefaultConnectionString].ConnectionString;
readonly static SqlConnectionStringBuilder MyBuilder = new SqlConnectionStringBuilder(ConnectionString);
public static void InstallServices(SqlFeatures sqlFeatures)
{
SqlServices.Install(MyBuilder.InitialCatalog, sqlFeatures, ConnectionString);
}
public static void UninstallServices(SqlFeatures sqlFeatures)
{
SqlServices.Uninstall(MyBuilder.InitialCatalog, sqlFeatures, ConnectionString);
}
}
}
Thanks to @ImarSpaanjaars http://imar.spaanjaars.com/563/using-entity-framework-code-first-and-aspnet-membership-together.
精彩评论