I have two tables:
class company
{
prop Id //PK
prop EskaId //PK
}
class policy
{
prop Id //PK
prop CompanyEskaId //FK
}
I want to link CompanyEskaId with EskaId using Fluent API.
I've tried
HasRequired(b => b.CompanyObj).WithMany().HasForeignKey(c => c.CompanyEskaId);
But in this case how can determine the target PK is EskaId, not the Id
In EF6 an Entity has only a single Key so you would have to make EskaId the key of CompanyObj.
EF Core supports Alternate Keys where an entity has multiple keys and a Foreign Key can refer to any key. eg:
internal class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>()
.HasOne(p => p.Blog)
.WithMany(b => b.Posts)
.HasForeignKey(p => p.BlogUrl)
.HasPrincipalKey(b => b.Url);
}
}
I have looked at the following:
Entity framework code first map multiple complex types of the same type to a table
Given the example code:
[Table("TXLifeRequest", Schema = "txlife")]
public partial class TXLifeRequest
{
public virtual OLI_LU_BOOLEAN PendingResponseOK { get; set; }
...
}
[Table("OLI_LU_BOOLEAN", Schema = "txlife")]
public partial class OLI_LU_BOOLEAN {
public string tc { get; set; }
public string Value { get; set; }
}
I would like to structure the database so that the OLI_LU_BOOLEAN is not in a new table, rather to be two new columns in the TXLifeRequest table as something like TXLifeRequest.PendingResponseOK_tc and PendingResponseOK _Value.
There is no fluent code in the existing context. Is there a way to do this either by fluent or attrubutes so that the class structure is intact but the tables are combined?
Update:
I have tried the following but it creates a new table TXLifeRequest1 for all of the OLI_LU_BOOLEAN properties. How would I specify these as properties of same table?
modelBuilder.ComplexType<OLI_LU_BOOLEAN>()
CreateTable("imsparamed.TXLifeRequest1",
c => new
{
Id = c.Int(nullable: false, identity: true),
PendingResponseOK_Value = c.String(),
PendingResponseOK_Id = c.Int(nullable: false)
})
The solution is to create a complex type:
modelBuilder.ComplexType<OLI_LU_BOOLEAN>().Ignore(i => i.Value);
Can't seem to find an answer to this one, even though what I'm doing seems like it would be common and important to most developers. In most systems with user accounts, the user table is tied to other tables in the database. That's all I want. I'm using MSSQL Express 2012 and VS 2013.
I have a class library where I'm using the code-first approach to generate tables. I moved the IdentityModel class from the MVC project to this class library as well. Everything works separately - my tables are generated and work fine, and the Identity tables are generated when I register a new user.
However, now I need one of my entities/tables tied to the ApplicationUser in a 1-1 relationship, but adding the field like so prevents the Identity tables from being generated:
public class ApplicationUser : IdentityUser
{
//***custom field
public MyPortfolio Portfolio { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
return userIdentity;
}
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("name=MyDataModel", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
base.OnModelCreating(modelBuilder);
//sql output log
Database.Log = s => Debug.Write(s);
}
}
..."MyPortfolio" is just plain entity:
public class MyPortfolio
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[StringLength(45, MinimumLength = 3)]
public string Name { get; set; }
public Boolean IsMaster { get; set; }
//public ApplicationUser User { get; set; } //threw exception!
}
I don't know too much about Identity, but have read that Migrations might be the answer. I'd rather avoid any further complexity if possible. Will that really be necessary? I am in early development and will be dropping/re-creating the tables many more times.
UPDATE 1:
OK, I added everything like adricadar described below. Here's what happened...
When adding migrations I had to select my class library from the "Default project" dropdown in the Package Manager Console. When doing Enable-Migrations, I got the following error:
More than one context type was found in the assembly 'MyProject.Data'.
To enable migrations for 'MyProject.Models.ApplicationDbContext', use
Enable-Migrations -ContextTypeName
MyProject.Models.ApplicationDbContext. To enable migrations for
'MyProject.Data.MyDataModel', use Enable-Migrations -ContextTypeName
MyProject.Data.MyDataModel.
...so I did the following:
Enable-Migrations -ContextTypeName
MyProject.Models.ApplicationDbContext
...which as expected, created the Configuration class and an "InitialCreate" class for the AspNetUser* tables.
I then ran "Add-Migration UserPortofolioRelation", which generated the DbMigration class with Up() and Down(). Up and Down both define all of the tables I've defined in MyDataModel. I now see the relationship between MyPortfolio and AspNetUsers in Up():
CreateTable(
"dbo.MyPortfolio",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(maxLength: 45),
IsMaster = c.Boolean(nullable: false),
UserId = c.String(nullable: false, maxLength: 128),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.AspNetUsers", t => t.UserId)
.Index(t => t.UserId);
When I run Update-Database, I get the following error:
Applying explicit migrations:
[201504141316068_UserPortofolioRelation]. Applying explicit migration:
201504141316068_UserPortofolioRelation.
System.Data.SqlClient.SqlException (0x80131904): There is already an
object named 'MyPortfolio' in the database.
The extent of my knowledge of Migrations is this basic tutorial:
https://msdn.microsoft.com/en-us/data/jj591621.aspx
This worked for me, and only the new fields were defined in the generated migrations code, not commands to drop and create all the tables.
UPDATE 2:
I followed this tutorial, which seemed to explain things a little more clearly when trying to work with migrations on multiple data contexts:
http://www.dotnet-tricks.com/Tutorial/entityframework/2VOa140214-Entity-Framework-6-Code-First-Migrations-with-Multiple-Data-Contexts.html
I ran this command:
Enable-Migrations -ContextTypeName
MyProject.Models.ApplicationDbContext
The following Configuration was created:
internal sealed class Configuration : DbMigrationsConfiguration<MyProject.Models.ApplicationDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(MyProject.Models.ApplicationDbContext context)
{
}
}
...looking good. Then I ran this:
Add-Migration -Configuration MyProject.Data.Migrations.Configuration
MigrationIdentity
...which generated this file:
namespace MyProject.Data.Migrations
{
using System;
using System.Data.Entity.Migrations;
public partial class MigrationIdentity : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.MyPortfolio",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(maxLength: 45),
IsMaster = c.Boolean(nullable: false),
UserId = c.String(nullable: false, maxLength: 128),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.AspNetUsers", t => t.UserId)
.Index(t => t.UserId);
...my other non-identity entities...
CreateTable(
"dbo.AspNetUsers",
c => new
{
Id = c.String(nullable: false, maxLength: 128),
Email = c.String(maxLength: 256),
EmailConfirmed = c.Boolean(nullable: false),
PasswordHash = c.String(),
SecurityStamp = c.String(),
PhoneNumber = c.String(),
PhoneNumberConfirmed = c.Boolean(nullable: false),
TwoFactorEnabled = c.Boolean(nullable: false),
LockoutEndDateUtc = c.DateTime(),
LockoutEnabled = c.Boolean(nullable: false),
AccessFailedCount = c.Int(nullable: false),
UserName = c.String(nullable: false, maxLength: 256),
})
.PrimaryKey(t => t.Id)
.Index(t => t.UserName, unique: true, name: "UserNameIndex");
...other Identity entities/tables...
}
public override void Down()
{
...everything you'd expect...
}
}
}
Awesome! All tables/entities in one file! So I ran it:
Update-Database -Configuration MyProject.Data.Migrations.Configuration
-Verbose
...and bam! It generated all the tables with the UserId FK on the MyPortfolio table. All seems to be great with the world. Nothing can stop me now! Then I ran it and got this exception:
One or more validation errors were detected during model generation:
System.Data.Entity.ModelConfiguration.ModelValidationException
MyProject.Data.IdentityUserLogin: : EntityType 'IdentityUserLogin' has
no key defined. Define the key for this EntityType.
MyProject.Data.IdentityUserRole: : EntityType 'IdentityUserRole' has
no key defined. Define the key for this EntityType.
IdentityUserLogins: EntityType: EntitySet 'IdentityUserLogins' is
based on type 'IdentityUserLogin' that has no keys defined.
IdentityUserRoles: EntityType: EntitySet 'IdentityUserRoles' is based
on type 'IdentityUserRole' that has no keys defined.
A quick Google brought me back to Stack Exchange, naturally: EntityType 'IdentityUserLogin' has no key defined. Define the key for this EntityType
The accepted answer outlines a whole slew of new possible angles to play, to try and get this to work right. This brings me back to my original question. Can I do this without migrations. Is that possible, in any way? With the level of complexity this comes with, I'm seriously debating "rolling my own" authentication, if not. I've already spent an exorbitant amount of time trying to simply tie a code-first entity to the Identity user. Each new door presents two more to go through. It just doesn't seem worth it...but maybe they'll clean this up a bit in the next release.
You can specify the relationgship in OnModelCreating.
Try to use one DbContext per database. Usually you make different DbContexts for different databases, not for same.
Move all your entities in ApplicationDbContext and follow the instruction below.
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("name=MyDataModel", throwIfV1Schema: false)
{
}
public DbSet<MyPortfolio> Portfolios { get; set; }
// The rest of the entities
// goes here
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<MyPortfolio>()
.HasRequired(m => m.User )
.WithOptional(m => m.Portfolio )
.Map(m => { m.MapKey("UserId"); });
base.OnModelCreating(modelBuilder);
//sql output log
Database.Log = s => Debug.Write(s);
}
}
Than you have to update your database, with migration, it's very easy. Open Package Manager Console in Visual Studio and enter this commands in order.
Enable-Migration
Add-Migration UserPortofolioRelation`
Update-Database
I am using EF6 and trying to use Code First with Migrations against a SQL DB.
Is it possible using a data annotation in my POCO class to specify that the default value of a Boolean or Bit field should be true?
I know I could modify the data migrations code to add it to the specific migration class but would like to avoid that.
check this: How to set default value for POCO's in EF CF?
You can do this through Migration step.
public class Test
{
(...)
public bool TestProperty { get; set; }
(...)
}
public partial class AddTestClass : DbMigration
{
public override void Up()
{
CreateTable(
"Test",
c => new
{
(...)
TestProperty = c => c.Boolean(nullable: false, defaultValue: false)
(...)
})
(...)
}
public overide void Down()
{
// Commands for when Migration is brought down
}
}
`
When i try to SaveChanges() to insert a new entity, I get the following exception.
System.Data.Entity.Infrastructure.DbUpdateException : An error occurred while updating the entries. See the inner exception for details.
----> System.Data.UpdateException : An error occurred while updating the entries. See the inner exception for details.
----> System.Data.SqlClient.SqlException : Invalid column name 'LD_Content'.
Invalid column name 'LD_File'.
I'm not using Code First nor Database First approach here. The database is preexisting, but the entity code is generated from custom templates.
These are the DB tables:
CREATE TABLE [dbo].[Licences](
[L_ID] [uniqueidentifier] NOT NULL,
CONSTRAINT [PK_Licences] PRIMARY KEY NONCLUSTERED
(
[L_ID] ASC
))
GO
ALTER TABLE [dbo].[Licences] WITH CHECK ADD CONSTRAINT [FK_Licences_LicenceData] FOREIGN KEY([L_ID])
REFERENCES [dbo].[LicenceData] ([LD_ID])
GO
CREATE TABLE [dbo].[LicenceData](
[LD_ID] [uniqueidentifier] NOT NULL,
[LD_Content] [varbinary](max) NOT NULL,
[LD_File] [varbinary](max) NULL,
CONSTRAINT [PK_LicenceData] PRIMARY KEY NONCLUSTERED
(
[LD_ID] ASC
))
These are the entities:
[Table("Licences")]
public class Licence
{
[Required, Display(Name="ID"), Column("L_ID")]
public Guid ID { get; set; }
public virtual LicenceFile File { get; set; }
[Required, Display(Name = "Content"), Column("LD_Content")]
public virtual string Content { get; set; }
}
[Table("LicenceData")]
public class LicenceFile
{
[Required, Display(Name = "ID"), Column("LD_ID")]
public Guid ID { get; set; }
[Display(Name = "File"), Column("LD_File")]
public byte[] File { get; set; }
}
And this is the mapping:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Licence>()
.Map(m =>
{
m.Properties(licence => new {licence.Content});
m.ToTable("LicenceData");
});
modelBuilder.Entity<Licence>().HasRequired(i => i.File).WithRequiredPrincipal();
base.OnModelCreating(modelBuilder);
}
The entity is created with its navigation property set:
new Licence
{
Content = "content",
File = new LicenceFile()
}
Summing up, there are two tables in one-to-one relationship. One of the entities, Licence, maps to its table (Licences) and also to one of the columns of the other table (entity splitting). The second entity, LicenceFile, maps to the ramaining columns of the other table (LienceData).
What has gone wrong here?