I have the following data table:
CREATE TABLE [dbo].[AuthorizeAttrib]
(
[Id] [UNIQUEIDENTIFIER] NOT NULL
, [ControllerName] [VARCHAR](100) NOT NULL
, [ActionName] [VARCHAR](100) NULL
, CONSTRAINT [PK_AuthorizeAttrib] PRIMARY KEY CLUSTERED ( [Id] ASC )
)
ON [PRIMARY];
In code I have the following:
public class StsDatabase : MembershipRebootDbContext<StsUser, StsGroup>
{
public StsDatabase() : this("name=MembershipReboot") { }
public StsDatabase(string name) : base(name) { this.RegisterUserAccountChildTablesForDelete<StsUser>(); }
public DbSet<AuthorizeAttrib> AuthorizeAttribs { get; set; }
public DbSet<Role> Roles { get; set; }
public DbSet<RuleSet> RuleSets { get; set; }
public DbSet<RuleSetRole> RuleSetRoles { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.ConfigureMembershipRebootUserAccounts<StsUser>();
modelBuilder.ConfigureMembershipRebootGroups<StsGroup>();
modelBuilder.Configurations.Add(new AuthorizeAttribMap());
modelBuilder.Configurations.Add(new RoleMap());
modelBuilder.Configurations.Add(new RuleSetMap());
modelBuilder.Configurations.Add(new RuleSetRoleMap());
}
}
And the AuthorizeAttribMap looks like:
public class AuthorizeAttribMap : EntityTypeConfiguration<AuthorizeAttrib>
{
public AuthorizeAttribMap()
{
// Primary Key
this.HasKey(t => t.Id);
// Properties
this.Property(t => t.ControllerName)
.IsRequired()
.HasMaxLength(100);
this.Property(t => t.ActionName)
.HasMaxLength(100);
// Table & Column Mappings
this.ToTable("AuthorizeAttrib");
this.Property(t => t.Id).HasColumnName("Id");
this.Property(t => t.ControllerName).HasColumnName("ControllerName");
this.Property(t => t.ActionName).HasColumnName("ActionName");
}
}
I've even tried running with AND without the following:
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
Nothing seems to be working. When I break on the code before it executes and copy the SQL then run it in SQL Mangler it runs fine. The SQL produced by LINQ:
SELECT [Extent1].[Id] AS [Id]
, [Extent1].[ControllerName] AS [ControllerName]
, [Extent1].[ActionName] AS [ActionName]
FROM [dbo].[AuthorizeAttrib] AS [Extent1];
I am scratching my head as to what else would cause this challenge!
Any ideas?
When the build/publish script ran, the wrong web.config was pulled in. Still pointing to the Dev DB instead of the Security Dev DB. Note to self: ALWAYS check the web.configs. Too many moving parts!
Related
I am upgrading the security in an xaf application as per DevExpress help
My situation is complicated because I have a mapping from the payroll table to the user table.
I have found in the past that this mapping caused a need for some configuration classes
Thus I have the following in the DbContext
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.Add(new RoleConfiguration());
modelBuilder.Configurations.Add(new UserConfiguration());
}
public class UserConfiguration : EntityTypeConfiguration<PermissionPolicyUser>
{
public UserConfiguration()
{
HasMany(x => x.Roles).WithMany(y=> y.Users)
.Map(m =>
{
m.MapLeftKey("PermissionPolicyRole_ID");
m.MapRightKey("PermissionPolicyUser_ID");
m.ToTable("PermissionPolicyUserPermissionPolicyRoles");
});
}
}
public class RoleConfiguration : EntityTypeConfiguration<PermissionPolicyRole>
{
public RoleConfiguration()
{
HasMany(x => x.Users).WithMany(y=> y.Roles)
.Map(m =>
{
m.MapLeftKey("PermissionPolicyUser_ID");
m.MapRightKey("PermissionPolicyRole_ID");
m.ToTable("PermissionPolicyUserPermissionPolicyRoles");
});
}
}
When I generate the migration I was surprised to see the primary key columns reordered
DropPrimaryKey("dbo.PermissionPolicyUserPermissionPolicyRoles");
AddPrimaryKey("dbo.PermissionPolicyUserPermissionPolicyRoles", new[] { "PermissionPolicyRole_ID", "PermissionPolicyUser_ID" });
My question is why did this happen and does it matter?
I am using Asp.Net Identity 2.0 in my MVC 5 project.
Why is column PhoneNumber using [nvarchar](max) in SQL Server database table [dbo].[AspNetUsers]?
Can I change this to [nvarchar](64), for example?
I created a class ApplicationUser : IdentityUser in which I override property PhoneNumber with attribute [MaxLength(64)].
public class ApplicationUser : IdentityUser
{
[MaxLength(64)]
public override string PhoneNumber { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
return userIdentity;
}
}
You should be able to specify custom length using the modelBuilder in the ApplicationDbContext
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
static ApplicationDbContext()
{
// Set the database intializer which is run once during application start
// This seeds the database with admin user credentials and admin role
Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Properties<string>()
.Where(x => x.Name == "PhoneNumber")
.Configure(c => c.HasMaxLength(64));
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
I have tested it and it works!
For more information about manipulating EF6 mappings you can check out this link:
http://msdn.microsoft.com/en-us/data/jj819164#classes
yes you can change, just limit nvarchar if you dont want to exceed that number because data store size of nvarchar is equal to two times the actual length of data entered + 2 bytes.
ex : max or 64 wont effect size if you enter 5 char string
I am trying to use Guid's instead of strings for my primary key and have followed the following posts: How to change type of id in Microsoft.AspNet.Identity.EntityFramework.IdentityUser and
How to change type of id in Microsoft.AspNet.Identity.EntityFramework.IdentityUser
I updated to the latest prerelease packages of aspnet identity
Microsoft ASP.NET Identity Core 2.0.0-beta1
Microsoft ASP.NET Identity EntityFramework 2.0.0-beta1
and edited my User to allow for Guid's instead of the default string, I then created my own dbContext and usermanager, however every time I try to login I get the following error:
System.Data.SqlClient.SqlException: Operand type clash:
uniqueidentifier is incompatible with int
for this line:
var user = await UserManager.FindAsync(model.UserName,
model.Password);
I have checked to make sure that all the fields in the database are definitely uniqueidentifiers and I'm not sure what to try next, below is the code I am currently using:
User objects:
public class GuidRole : IdentityRole<Guid, GuidUserRole>
{
public GuidRole()
{
Id = Guid.NewGuid();
}
public GuidRole(string name) : this() { Name = name; }
}
public class GuidUserRole : IdentityUserRole<Guid> { }
public class GuidUserClaim : IdentityUserClaim<Guid> { }
public class GuidUserLogin : IdentityUserLogin<Guid> { }
public class User : IdentityUser<Guid, GuidUserLogin, GuidUserRole, GuidUserClaim>
{
public User()
{
Id = Guid.NewGuid();
}
public User(string name) : this() { UserName = name; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
dbContext:
public class newDbContext : IdentityDbContext<User, GuidRole, Guid, GuidUserLogin, GuidUserRole, GuidUserClaim>
{
public newDbContext()
: base(nameOrConnectionString: "defaultConnection") { }
public newDbContext(string connectionString)
: base(nameOrConnectionString: connectionString) { }
static newDbContext()
{
Database.SetInitializer<newDbContext>(null);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Use singular table names
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<User>().ToTable("User").Property(p => p.Id).HasColumnName("UserID");
modelBuilder.Entity<User>().Property(p => p.Email).HasColumnName("EmailAddress");
modelBuilder.Entity<GuidUserRole>().HasKey(r => new { r.RoleId, r.UserId });
modelBuilder.Entity<GuidUserRole>().ToTable("UserRole");
modelBuilder.Entity<GuidUserRole>().Property(r => r.UserId).HasColumnName("UserID");
modelBuilder.Entity<GuidUserRole>().Property(r => r.RoleId).HasColumnName("RoleID");
modelBuilder.Entity<GuidUserLogin>().ToTable("UserLogin");
modelBuilder.Entity<GuidUserLogin>().Property(r => r.UserId).HasColumnName("UserID");
modelBuilder.Entity<GuidUserClaim>().ToTable("UserClaim");
modelBuilder.Entity<GuidUserClaim>().Property(r => r.Id).HasColumnName("UserClaimID");
modelBuilder.Entity<GuidRole>().HasKey<Guid>(r => r.Id);
modelBuilder.Entity<GuidRole>().ToTable("Role");
modelBuilder.Entity<GuidRole>().Property(r => r.Id).HasColumnName("RoleID");
Configuration.ProxyCreationEnabled = false;
Configuration.LazyLoadingEnabled = false;
}
}
and finally the user manager:
public class ApplicationUserManager : UserManager<User, Guid>
{
public ApplicationUserManager(string connectionString)
: base(new UserStore<User, GuidRole, Guid, GuidUserLogin, GuidUserRole, GuidUserClaim>(new newDbContext()))
{
UserValidator = new UserValidator<User, Guid>(this) { AllowOnlyAlphanumericUserNames = false };
}
}
Thanks to Hao Kung's comment I individually went through the table and property mappings until I got to the UserClaims table. Turns out I had the field type set to uniqueidentifier in the database, however this still needed to be an int. Changing it fixed the problem!
I know this question might be duplicated, but I haven't found any solution for my problem yet.
I have:
protected void Application_Start()
{
Database.SetInitializer(new DatabaseSeeder());
DatabaseContext c = new DatabaseContext();
c.Database.Initialize(true);
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
my database seeder is:
public class DatabaseSeeder : DropCreateDatabaseAlways<DatabaseContextBase>
{
protected override void Seed(DatabaseContextBase context)
{
base.Seed(context);
var roles = new[] {"Admin", "User"};
foreach (var role in roles)
{
context.Roles.Add(new UserRole {FullName = role});
}
context.SaveChanges();
}
}
and my context is:
public abstract class DatabaseContextBase : DbContext
{
public DbSet<UserRole> Roles { get; set; }
public DbSet<UserAndPermissionInGroup> UserAndPermissions { get; set; }
public DbSet<GeneralUser> Users { get; set; }
public DbSet<Group> Groups { get; set; }
public DbSet<Forum> Forums { get; set; }
public DatabaseContextBase() :base("ForumDb")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Comment>()
.HasRequired(e => e.Owner)
.WithMany(t => t.Comments)
.HasForeignKey(e => e.OwnerId)
.WillCascadeOnDelete(false);
}
}
And finally:
public class DatabaseContext : DatabaseContextBase
{
}
The problem is that, even with this initializer, I get the following error:
The model backing the 'DatabaseContext' context has changed since the
database was created. Consider using Code First Migrations to update
the database
I am using EF 5 code first in an ASP.NET MVC 3 project. Any suggestions?
It looks like Database.SetInitializer does not work for derived types. I changed the initializer from
public class DatabaseSeeder : DropCreateDatabaseAlways<DatabaseContextBase>
to
public class DatabaseSeeder : DropCreateDatabaseAlways<DatabaseContext>
and now the code:
Database.SetInitializer(new DatabaseSeeder());
DatabaseContext c = new DatabaseContext();
c.Database.Initialize(true);
works pretty well. Thanks for all answers.
If you are good with losing your data, when you make changes to your models, try following.
DatabaseSeeder : DropCreateDatabaseIfModelChanges<DatabaseContextBase>
Instead of
DatabaseSeeder : DropCreateDatabaseAlways<DatabaseContextBase>
That way, when you make changes to your model, your database will be recreated using your up to date models and seed method will be called.
If you want to preserve your data, you should start reading about migrations.
Code-First Migrations
Automatic Migrations
Something like the following?
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions
.Remove<System.Data.Entity.Database.IncludeMetadataConvention>()
.Entity<Comment>()
.HasRequired(e => e.Owner)
.WithMany(t => t.Comments)
.HasForeignKey(e => e.OwnerId)
.WillCascadeOnDelete(false);
}
I'm not sure if this would work, but could you do something like this?
DatabaseSeeder<TContextType> : DropCreateDatabaseAlways<TContextType> where TContextType : DatabaseContextBase
I'm working with an existing database and using EF 4.3 Code First. I have an entity hierarchy that looks like this, where Note is the base class:
Note
- CompanyNote
- OrderNote
- etc
I'm using TPH with a discriminator column having the following mapping:
Map<CompanyNote>(t => t.Requires("type").HasValue("company"));
Map<OrderNote>(t => t.Requires("type").HasValue("order"));
The database type of type is char(18). EF generates sql as if its nchar:
SELECT /* columns */
FROM [dbo].[notes] AS [Extent1]
WHERE [Extent1].[type] = N'company'
That N is a problem because this table has many thousands of rows and it prevents SQL from using an index. I need to query to look this way:
SELECT /* columns */
FROM [dbo].[notes] AS [Extent1]
WHERE [Extent1].[type] = 'company'
Here's what I've tried so far:
Adding a Type property and mapping it with
Property(t => t.Type).IsFixedLength().HasMaxLength(18).IsUnicode(false);
Adding column configuration to the inheritance mapping with
Map<CompanyNote>(t => t.Requires("type").HasValue("company").IsFixedLength().HasMaxLength(18).IsUnicode(false));
Neither changes made a difference. Unfortunately, I can't change the database column type to nchar.
How can I tell Entity Framework that the discriminator column is of type char?
Update: Here's a complete example
[TestFixture]
public class TphMappingFixture
{
[Test]
public void CompanyNotesQueryShouldNotHaveUnicodeDiscriminator()
{
string sql;
using (TphTestContext context = new TphTestContext())
{
sql = context.CompanyNotes.ToString();
}
Console.WriteLine(sql);
/* sql is:
SELECT
'0X0X' AS [C1],
[Extent1].[id] AS [id],
[Extent1].[text] AS [text]
FROM [dbo].[notes] AS [Extent1]
WHERE [Extent1].[type] = N'company'
*/
Assert.That(!sql.Contains("N'company'"));
}
}
public abstract class TphTestNote
{
public int Id { get; set; }
public string Text { get; set; }
}
public class TphTestCompanyNote : TphTestNote
{
}
public class TphTestOrderNote : TphTestNote
{
}
public class TphTestNoteMap : EntityTypeConfiguration<TphTestNote>
{
public TphTestNoteMap()
{
HasKey(t => t.Id);
Property(t => t.Text)
.HasMaxLength(254)
.IsUnicode(false);
ToTable("notes");
Property(t => t.Id).HasColumnName("id");
Property(t => t.Text).HasColumnName("text");
Map<TphTestCompanyNote>(t => t.Requires("type").HasValue("company").IsUnicode(false));
Map<TphTestOrderNote>(t => t.Requires("type").HasValue("order").IsUnicode(false));
}
}
public class TphTestContext : DbContext
{
static TphTestContext()
{
Database.SetInitializer<TphTestContext>(null);
}
public DbSet<TphTestCompanyNote> CompanyNotes { get; set; }
public DbSet<TphTestOrderNote> OrderNotes { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new TphTestNoteMap());
}
}
I'm still not sure why I'm seeing different results than #Slauma, but I finally found something that works for me. I explicitly set the column type to char in the inheritance mapping.
Map<TphTestCompanyNote>(t => t.Requires("type")
.HasValue("company")
.HasColumnType("char"));
Map<TphTestOrderNote>(t => t.Requires("type")
.HasValue("order")
.HasColumnType("char"));
And the resulting SQL:
SELECT
'0X0X' AS [C1],
[Extent1].[id] AS [id],
[Extent1].[text] AS [text]
FROM [dbo].[notes] AS [Extent1]
WHERE [Extent1].[type] = 'company'
I can't reproduce the use of a Unicode string in the SQL query. Test application (Console app with EF 4.3.1):
using System;
using System.Data.Entity;
using System.Linq;
namespace EF43TPH
{
public abstract class Note
{
public int Id { get; set; }
public string Name { get; set; }
}
public class CompanyNote : Note
{
public string ExtendedName { get; set; }
}
public class OrderNote : Note
{
public string AnotherExtendedName { get; set; }
}
public class MyContext : DbContext
{
public DbSet<Note> Notes { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<CompanyNote>()
.Map<CompanyNote>(t => t.Requires("type").HasValue("company"));
modelBuilder.Entity<OrderNote>()
.Map<OrderNote>(t => t.Requires("type").HasValue("order"));
}
}
class Program
{
static void Main(string[] args)
{
Database.SetInitializer(new DropCreateDatabaseAlways<MyContext>());
using (var ctx = new MyContext())
{
try
{
var query = ctx.Notes.OfType<CompanyNote>();
var queryString = query.ToString();
}
catch (Exception e)
{
throw;
}
}
}
}
}
The SQL query I get in queryString is:
SELECT
'0X0X' AS [C1],
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
[Extent1].[ExtendedName] AS [ExtendedName]
FROM [dbo].[Notes] AS [Extent1]
WHERE [Extent1].[type] = 'company'
What is different between this test and your code?