Table per Concrete Type Mapping Issue in EF Code First 4.2 - entity-framework

I'm getting a EntityType 'User' has no key defined. Define the key for this EntityType error.
Model:
public abstract class KeyedEntityBase
{
public int ID { get; private set; }
}
public class User : KeyedEntityBase
{
public string UserName { get; private set; }
public string EmailAddress { get; private set; }
}
Context:
public class LSBPortalContext : DbContext
{
public LSBPortalContext()
: base("LSBPortalDB")
{
}
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("User");
});
base.OnModelCreating(modelBuilder);
}
}

The issues was that I didn't actually map the KeyedEntityBase class. Once I did that it all worked properly.

Related

Including a Model from different DbContext

I am not sure how to achieve the relation between 2 DbContexts. PurchaseOrderDbContext is a Code first approach & AgencyDbContext is an existing database. How can I include the "Division" from AgencyDbContext based on PurchaseOrder DivisionId?
To start off here is a very simplified version of my code.
Purchase Order Model
namespace Website.Models.PurchaseOrders
{
public class PurchaseOrder
{
public int ID { get; set; }
public DateTime OrderDate { get; set; }
public string Name { get; set; }
public int DivisionId { get; set; }
public int StatusID { get; set; }
public Agency.Division Division { get; set; }
}
}
Division Model (this is in a different DbContext)
namespace Website.Models.Agency
{
public class Division
{
public int DivisionId { get; set; }
public string DivisionName { get; set; }
public string DivisionShortName { get; set; }
public string DivisionAbbrev { get; set; }
public int? DivisionDirectorEmpId { get; set; }
}
}
Agency DbContext
namespace Website.Models.Agency
{
public class AgencyDbContext : DbContext
{
public Agency DbContext(DbContextOptions<AgencyDbContext> options) : base(options)
{
}
public virtual DbSet<Division> Division { get; set; }
public virtual DbSet<Section> Section { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
}
}
PurchaseOrderDbContext
namespace Website.Models.PurchaseOrders
{
public class PurchaseOrderDbContext : DbContext
{
public PurchaseOrderDbContext(DbContextOptions<PurchaseOrderDbContext> options) : base(options)
{}
public DbSet<Status> Statuses { get; set; }
public DbSet<PurchaseOrder> PurchaseOrder { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
}
}
I get an the error InvalidOperationException: Lambda expression used inside Include is not valid. This is referring to the Include extension on Division.
var purchaseOrder = _context.PurchaseOrder
.Include(p => p.Division)
.Include(p => p.Status)
.OrderByDescending(p => p.OrderDate);
Thank you in advance!
Probably the only way to resolve is to make a query to the first context for items you are looking for, and then populate Division property with entries from second context
public class PurchaseOrderService
{
private readonly PurchaseOrderDbContext purchaseOrderDbContext;
private readonly AgencyDbContext agencyDbContext;
public PurchaseOrderService(PurchaseOrderDbContext purchaseOrderDbContext,
AgencyDbContext agencyDbContext)
{
this.purchaseOrderDbContext = purchaseOrderDbContext;
this.agencyDbContext = agencyDbContext;
}
public PurchaseOrder Get(int id)
{
var purchaseOrder = purchaseOrderDbContext.PurchaseOrder.FirstOrDefault(x => x.ID == id);
if (purchaseOrder == null)
{
return null;
}
purchaseOrder.Division = agencyDbContext.Division.FirstOrDefault(x => x.DivisionId == purchaseOrder.DivisionId);
return purchaseOrder;
}
}

Add TPT Inherited Code First Model to Linq Fluent API

I'm having problems extending the Fluent API to my inheritance classes. I have taken the TPT (table per type) method and each type of the inheritance has a table. I like table per type because the database is fully normalized and easy to maintain. I am not getting the inherited model ServiceCompany to work with the Fluent API.
Base Abstract Class
public abstract class Vendor
{
[Key]
public int VendorID { get; set; }
[Required]
public string CompanyName { get; set; }
[Required]
public int StreetNumber { get; set; }
[Required]
public string StreetName { get; set; }
}
Inherited ServiceCompany Class from Vendor
[Table("ServiceCompanies")]
public class ServiceCompany : Vendor
{
public string ACHClaim { get; set; }
public virtual ICollection<SubContractorCompany> SubContractorCompanies { get; set; }
public virtual ICollection<ServiceCompanyUser> SubContractorUsers { get; set; }
}
Where I added the entity models to enable the Fluent API with onModelCreating()
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public DbSet<Vendor> Vendors { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ServiceCompany>().ToTable("ServiceCompanies");
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
I would like to be able to do something like this with the fluent API.
var ListofServiceCompanies = db.ServiceCompanies.All()
and not like this
var ListofServiceCompanies = db.Vendor.SelectMany( Vendor is a ServiceComapny...etc)
I prefer to set up the entities correctly and make the code nice and easy to use. Any insight or knowledge is appreciated.
You can do that by calling OfType extension method like below:
var ListofServiceCompanies = db.Vendor.OfType<Vendor>().ToList();
Or you can just add a DbSet<ServiceCompany> ServiceCompanies { get; set; } into your DbContext so it will look like this:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public DbSet<Vendor> Vendors { get; set; }
public DbSet<ServiceCompany> ServiceCompanies { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ServiceCompany>().ToTable("ServiceCompanies");
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
Then just call:
var ListofServiceCompanies = db.ServiceCompanies.ToList();

How do I force generated many-to-many Relation tables to the correct schema?

I have tables parkpay.User and parkpay.Role. EF Code First automatically generates a third table linking the two for a many-to-many relationship, but it generates dbo.UserRole. How do I get it to make that table `parkpay.UserRole'?
Use EntityTypeConfiguration<> config many-to-many mappings.
public class User
{
public long Id { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public virtual ICollection<Role> Roles { get; set; }
}
public class Role
{
public long Id { get; set; }
public string Name { get; set; }
public virtual ICollection<User> Users { get; set; }
}
public class UserMapping : EntityTypeConfiguration<User>
{
public UserMapping()
{
ToTable("User", "parkpay");
HasKey(e => e.Id).Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
HasMany(e => e.Roles).WithMany(e => e.Users).Map(m => m.ToTable("UserRole", "parkpay").MapLeftKey("RoleId").MapRightKey("UserId"));
}
}
public class RoleMapping : EntityTypeConfiguration<Role>
{
public RoleMapping()
{
ToTable("Role", "parkpay");
HasKey(e => e.Id).Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
public class DatabaseContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new UserMapping());
modelBuilder.Configurations.Add(new RoleMapping());
base.OnModelCreating(modelBuilder);
}
}

Entity Framework 4.1 : The navigation property 'BusinessUser' declared on type 'Login' has been configured with conflicting multiplicities

I am having two entities
BusinessUser { Id(PK), Name,...}
Login { BusinessUserID(PK, FK), Email, Password, etc...}
Relationship between BusinessUser and Login is one-to-zero/one.
I am having following configurations
In BusinessUser EF configuration class
this.HasOptional(bu => bu.LoginInfo)
.WithOptionalPrincipal(l => l.BusinessUser);
In Login EF configuration class
this.HasRequired(l => l.BusinessUser)
.WithOptional(bu => bu.LoginInfo);
I am getting following exception
The navigation property 'BusinessUser' declared on type 'Login' has been configured
with conflicting multiplicities.
Where I am wrong with my one-to-one/zero configuration in EF 4.1 code first.
Update 1 : Following are my class structure
public class BusinessUser {
public virtual int ID { get; set; }
public virtual int BusinessID { get; set; }
public virtual Business Business { get; set; }
public Login LoginInfo { get; set; }
}
public class Login {
public virtual int BusinessUserID { get; set; }
public virtual string Email { get; set; }
public virtual string Password { get; set; }
public BUsinessUser BusinessUserInfo { get; set; }
}
Also I am looking for bi-directional.
Your BusinessUser must have relation configured as:
this.HasOptional(bu => bu.LoginInfo)
.WithRequired(l => l.BusinessUser);
Both configuration must be same (actually only one is needed) and the first configuration is incorrect because it is trying to define 0..1 - 0..1 relation.
How have you structured your classes ? Here's a sample with a relationship one-to-one/zero defined.
The result is :
BusinessUser { Id(PK), Name,...}
Login { BusinessUserID(PK, FK), Email, Password, etc...}
public class BusinessUser
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public virtual LoginInfo LoginInfo { get; set; }
}
public class LoginInfo
{
public int BusinessUserId { get; set; }
public virtual BusinessUser BusinessUser { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
Here is the DbContext and the Initializer
public class MyContext : DbContext
{
public DbSet<BusinessUser> BusinessUsers { get; set; }
public DbSet<LoginInfo> LoginInfos { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
//We define the key for the LoginInfo table
modelBuilder.Entity<LoginInfo>().HasKey(x => x.BusinessUserId);
modelBuilder.Entity<LoginInfo>().HasRequired(bu => bu.BusinessUser);
}
}
public class MyInitializer : DropCreateDatabaseIfModelChanges<MyContext>
{
protected override void Seed(MyContext context)
{
var businessUser = new BusinessUser();
businessUser.Email = "mymail#email.com";
businessUser.Name = "My Name";
businessUser.LoginInfo = new LoginInfo(){Username = "myusername", Password ="mypassword"};
context.BusinessUsers.Add(businessUser);
context.SaveChanges();
}
}

in entity framework code first, how to use KeyAttribute on multiple columns

I'm creating a POCO model to use with entity framework code first CTP5. I'm using the decoration to make a property map to a PK column. But how can I define a PK on more then one column, and specifically, how can I control order of the columns in the index? Is it a result of the order of properties in the class?
Thanks!
NOTE:
As of 2019 this answer became non-valid for later EntityFramework versions.
You can specify the column order in the attributes, for instance:
public class MyEntity
{
[Key, Column(Order=0)]
public int MyFirstKeyProperty { get; set; }
[Key, Column(Order=1)]
public int MySecondKeyProperty { get; set; }
[Key, Column(Order=2)]
public string MyThirdKeyProperty { get; set; }
// other properties
}
If you are using the Find method of a DbSet you must take this order for the key parameters into account.
To complete the correct answer submitted by Slauma, you can use the HasKey method to specify an order for composite primary keys as well:
public class User
{
public int UserId { get; set; }
public string Username { get; set; }
}
public class Ctp5Context : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().HasKey(u => new
{
u.UserId,
u.Username
});
}
}
If, like me, you prefer to use a configuration file you can do that in this way (based on Manavi's example):
public class User
{
public int UserId { get; set; }
public string Username { get; set; }
}
public class UserConfiguration : EntityTypeConfiguration<User>
{
public UserConfiguration()
{
ToTable("Users");
HasKey(x => new {x.UserId, x.Username});
}
}
Obviously you have to add the configuration file to your context:
public class Ctp5Context : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new UserConfiguration());
}
}
Use as a anonymous object:
modelBuilder.Entity<UserExamAttemptQuestion>().ToTable("Users").HasKey(o => new { o.UserId, o.Username });