Entity framework 代码优先&;Azure表存储的标识

Entity framework 代码优先&;Azure表存储的标识,entity-framework,azure,ef-code-first,azure-table-storage,asp.net-identity,Entity Framework,Azure,Ef Code First,Azure Table Storage,Asp.net Identity,我正在开发一个小型web应用程序,我刚刚进入开发阶段,需要开始做出数据库决策。我最初的计划是首先在Azure上使用MSSQL编写EF代码,因为它简化了使用数据库的过程。然而,在调查我在Azure上的数据库托管功能时,我发现Azure表存储为我打开了NoSQL的世界 虽然互联网上充斥着关于NoSQL特性的讨论,但我收集到的最大原因之一是NoSQL将整个对象作为一个整体存储在数据库中,而不会将数据分解成各种表,这对性能有好处。虽然这听起来很吸引人,但EF Code First通过自动将对象拉到一起并

我正在开发一个小型web应用程序,我刚刚进入开发阶段,需要开始做出数据库决策。我最初的计划是首先在Azure上使用MSSQL编写EF代码,因为它简化了使用数据库的过程。然而,在调查我在Azure上的数据库托管功能时,我发现Azure表存储为我打开了NoSQL的世界

虽然互联网上充斥着关于NoSQL特性的讨论,但我收集到的最大原因之一是NoSQL将整个对象作为一个整体存储在数据库中,而不会将数据分解成各种表,这对性能有好处。虽然这听起来很吸引人,但EF Code First通过自动将对象拉到一起并将对象分离到SQL数据库中而有效地消除了这个问题,开发人员无需担心查询

然而,我的主要问题是,我找不到任何文档可以在NoSQL数据库中使用EF代码优先和ASP.NET标识。由于我的应用程序目前使用的是Identity,我希望避免切换到其他应用程序

Q:是否可以在Azure表中首先使用代码和/或标识?


编辑:关于我的应用程序的一点介绍作为一种极端简化,我的应用程序允许我的用户通过混合和匹配预配置的数据类型来创建自定义配置文件。例如,用户可以将任意数量的Quote对象添加到其配置文件中,然后定义Quote的值(即“做你自己;其他人都已经被引用了”)。或者,他们可以使用电影对象来定义他们喜爱的电影的集合(即“标题:盗梦空间,年份:2010”)。平均而言,一个用户可以轻松地在其页面上拥有50个或更多这样的属性;他们可以拥有的财产数量没有限制


使用这个示例,我可以很容易地看到如何首先使用代码实现它(Profile有一个Quote对象列表和一个Movie对象列表)。我还不确定这将如何映射到NoSQL数据库,如Azure表。因此,考虑到我的应用程序的需要,我不确定从代码优先切换到NoSQL是否是一个合理的决定,因为我将失去这些功能。

实际上,你不能在Azure表存储中首先使用EF代码。也就是说,使用表存储通常是使用与先编写代码类似的方法来完成的,也就是说,您创建类,然后他们动态地创建表

请注意,对于表存储,不存在任何关系或类似关系。表存储甚至比其他NoSQL解决方案更简单,因为您不能在单个表“行”中存储复杂对象

您可能可以创建一个只使用表和/或blob存储的.net标识提供程序,但我找不到任何示例-我确定以前有一个codeplex项目,但现在找不到它


Gert Arnold的意思是同时使用SQL Azure和表存储(EF仅用于SQL Azure部分)。通过这种方式,您可以使用它们各自的优势—表存储存储存储大量简单结构化的数据,sql azure用于更复杂的数据部分(即需要关系)

,因此我们将有一个示例正好针对这种情况,使用AzureTable存储作为UserStore的无sql实现。基本上,您可以使用Azure存储API实现一个IUserStore。以下是实现登录/密码方法的基本实现,但不是全部:

public class AzureRole : TableEntity, IRole {
    public string Id { get; set; }
    public string Name { get; set; }
}

public class AzureLogin : TableEntity {
    public AzureLogin() {
        PartitionKey = Constants.IdentityPartitionKey;
        RowKey = Guid.NewGuid().ToString();
    }

    public AzureLogin(string ownerId, UserLoginInfo info) : this() {
        UserId = ownerId;
        LoginProvider = info.LoginProvider;
        ProviderKey = info.ProviderKey;
    }

    public string UserId { get; set; }
    public string ProviderKey { get; set; }
    public string LoginProvider { get; set; }
}

public class AzureUser : TableEntity, IUser {
    public AzureUser() {
        PartitionKey = Constants.IdentityPartitionKey;
        RowKey = Guid.NewGuid().ToString();
        Id = RowKey;
        Roles = new List<string>();
        Claims = new List<Claim>();
        Logins = new List<AzureLogin>();
    }

    public AzureUser(string userName) : this() {
        UserName = userName;
    }

    public string Id { get; set; }
    public string UserName { get; set; }
    public string PasswordHash { get; set; }
    public string SecurityStamp { get; set; }
    public IList<string> Roles { get; set; }
    public IList<AzureLogin> Logins { get; set; }
    public IList<Claim> Claims { get; set; }
}

public static class Constants {
    public const string IdentityPartitionKey = "ASP.NET Identity";
}

public class AzureStore : IUserStore<AzureUser>, IUserClaimStore<AzureUser>, IUserLoginStore<AzureUser>, IUserRoleStore<AzureUser>, IUserPasswordStore<AzureUser> {
    public AzureStore() {
        // Retrieve the storage account from the connection string.
        CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));

        // CreateAsync the table client.
        CloudTableClient tableClient = storageAccount.CreateCloudTableClient();

        // CreateAsync the table if it doesn't exist.
        CloudTable table = tableClient.GetTableReference("Identity");
        table.CreateIfNotExists();
        Table = table;

        BatchOperation = new TableBatchOperation();
    }

    public TableBatchOperation BatchOperation { get; set; }
    public CloudTable Table { get; set; }

    public void Dispose() {
    }

    public Task<IList<Claim>> GetClaimsAsync(AzureUser user) {
        return Task.FromResult(user.Claims);
    }

    public Task AddClaimAsync(AzureUser user, System.Security.Claims.Claim claim) {
        return Task.FromResult(0);
    }

    public Task RemoveClaimAsync(AzureUser user, System.Security.Claims.Claim claim) {
        return Task.FromResult(0);
    }

    Task IUserStore<AzureUser>.CreateAsync(AzureUser user) {
        TableOperation op = TableOperation.Insert(user);
        var result = Table.Execute(op);
        return Task.FromResult(0);
    }

    Task IUserStore<AzureUser>.UpdateAsync(AzureUser user) {
        TableOperation op = TableOperation.Replace(user);
        var result = Table.Execute(op);
        return Task.FromResult(0);
    }

    public Task<AzureUser> FindByIdAsync(string userId) {
        TableOperation op = TableOperation.Retrieve<AzureUser>(Constants.IdentityPartitionKey, userId);
        var result = Table.Execute(op);
        return Task.FromResult<AzureUser>(result.Result as AzureUser);
    }

    public Task<AzureUser> FindByNameAsync(string userName) {
        TableQuery<AzureUser> query = new TableQuery<AzureUser>().Where(TableQuery.GenerateFilterCondition("UserName", QueryComparisons.Equal, userName));
        return Task.FromResult(Table.ExecuteQuery(query).FirstOrDefault());
    }

    public Task AddLoginAsync(AzureUser user, UserLoginInfo login) {
        TableOperation op = TableOperation.Insert(new AzureLogin(user.Id, login));
        var result = Table.Execute(op);
        return Task.FromResult(0);
    }

    public Task RemoveLoginAsync(AzureUser user, UserLoginInfo login) {
        var al = Find(login);
        if (al != null) {
            TableOperation op = TableOperation.Delete(al);
            var result = Table.Execute(op);
        }
        return Task.FromResult(0);
    }

    public Task<IList<UserLoginInfo>> GetLoginsAsync(AzureUser user) {
        TableQuery<AzureLogin> query = new TableQuery<AzureLogin>()
            .Where(TableQuery.GenerateFilterCondition("UserId", QueryComparisons.Equal, user.Id))
            .Select(new string[] { "LoginProvider", "ProviderKey" });
        var results = Table.ExecuteQuery(query);
        IList<UserLoginInfo> logins = new List<UserLoginInfo>();
        foreach (var al in results) {
            logins.Add(new UserLoginInfo(al.LoginProvider, al.ProviderKey));
        }
        return Task.FromResult(logins);
    }

    private AzureLogin Find(UserLoginInfo login) {
        TableQuery<AzureLogin> query = new TableQuery<AzureLogin>()
            .Where(TableQuery.CombineFilters(
                TableQuery.GenerateFilterCondition("LoginProvider", QueryComparisons.Equal, login.LoginProvider),
                TableOperators.And,
                TableQuery.GenerateFilterCondition("ProviderKey", QueryComparisons.Equal, login.ProviderKey)))
            .Select(new string[] { "UserId" });
        return Table.ExecuteQuery(query).FirstOrDefault();
    }

    public Task<AzureUser> FindAsync(UserLoginInfo login) {
        var al = Find(login);
        if (al != null) {
            return FindByIdAsync(al.UserId);
        }
        return Task.FromResult<AzureUser>(null);
    }

    public Task AddToRoleAsync(AzureUser user, string role) {
        return Task.FromResult(0);
    }

    public Task RemoveFromRoleAsync(AzureUser user, string role) {
        return Task.FromResult(0);
    }

    public Task<IList<string>> GetRolesAsync(AzureUser user) {
        return Task.FromResult(user.Roles);
    }

    public Task<bool> IsInRoleAsync(AzureUser user, string role) {
        return Task.FromResult(false);
    }


    public Task DeleteAsync(AzureUser user) {
        throw new NotImplementedException();
    }

    public Task<string> GetPasswordHashAsync(AzureUser user) {
        return Task.FromResult(user.PasswordHash);
    }

    public Task<bool> HasPasswordAsync(AzureUser user) {
        return Task.FromResult(user.PasswordHash != null);
    }

    public Task SetPasswordHashAsync(AzureUser user, string passwordHash) {
        user.PasswordHash = passwordHash;
        return Task.FromResult(0);
    }
}
公共类AzureRole:TableEntity,IRole{ 公共字符串Id{get;set;} 公共字符串名称{get;set;} } 公共类AzureLogin:TableEntity{ 公共AzureLogin(){ PartitionKey=Constants.IdentityPartitionKey; RowKey=Guid.NewGuid().ToString(); } publicAzureLogin(字符串ownerId,UserLoginInfo):this(){ UserId=ownerId; LoginProvider=info.LoginProvider; ProviderKey=info.ProviderKey; } 公共字符串用户标识{get;set;} 公共字符串提供程序密钥{get;set;} 公共字符串登录提供程序{get;set;} } 公共类AzureUser:TableEntity,IUser{ 公共AzureUser(){ PartitionKey=Constants.IdentityPartitionKey; RowKey=Guid.NewGuid().ToString(); Id=行键; 角色=新列表(); 索赔=新列表(); 登录名=新列表(); } public AzureUser(字符串用户名):this(){ 用户名=用户名; } 公共字符串Id{get;set;} 公共字符串用户名{get;set;} 公共字符串密码哈希{get;set;} 公共字符串SecurityStamp{get;set;} 公共IList角色{get;set;} 公共IList登录名{get;set;} 公共IList声明{get;set;} } 公共静态类常量{ public const string IdentityPartitionKey=“ASP.NET Identity”; } 公共类AzureStore:IUserStore、IUserClaimStore、IUserLoginStore、IUserRoleStore、IUserPasswordStore{ 公共AzureStore(){ //从连接字符串中检索存储帐户。 CloudStorageAccount-storageAccount=CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting(“StorageConnectionString”); //创建异步表客户端。 CloudTableClient tableClient=storageAccount.CreateCloudTableClient(); //如果表不存在,则创建异步表。 CloudTable=tableClient.GetTableReference(“标识”); table.CreateIfNotExists(); 表=表; BatchOperation=新表BatchOperation(); } 公共TableBatchOperation批处理操作{get;set;} 公共云表{get;set;} 公共空间处置(){ } 公共任务GetClaimsAsync(AzureUser用户){ 返回Task.FromResult(user.Claims); } 公共任务addClaimesync(AzureUser用户,System.Security.Claims.Claims){ 返回Task.FromResult(0); } 公共图书馆