How do I get Entity Framework to query the right table? - c#

I've got a class defined
public class ReportClass
{
public int ID { get; set; }
public int ClassIndex { get; set; }
public string ClassName { get; set; }
public int CompanyID { get; set; }
}
and I set up a dbcontext.
public class ReportClassContext : DbContext
{
public DbSet<ReportClass> ReportClasses { get; set; }
}
When I first went to get records, the runtime tells me the database table doesn't exist: I check, and I see that the name of my DbSet doesn't match with the table. I switched the name to match:
public class ReportClassContext : DbContext
{
public DbSet<ReportClass> ReportClassesRealTable { get; set; }
}
but it is still querying against the non-existent table.
What am I doing wrong?

Use the table attribute like this:
[Table("ReportClassesRealTable")]
public class ReportClass
{
public int ID { get; set; }
public int ClassIndex { get; set; }
public string ClassName { get; set; }
public int CompanyID { get; set; }
}
This tells the EF what the actual table name is for your class, otherwise it attempts to use the plural form of your class name.

Let this be there as it is
public DbSet<ReportClass> ReportClasses { get; set; }
Now overrde the OnMoedlCreateing method to tell EF to map this class to a different table using fluent API. Add that method to your DBContext class
public class ReportClassContext : DbContext
{
public DbSet<ReportClass> ReportClasses { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ReportClass>().ToTable("ReportClassesRealTable");
}
}
This tells EF that when you query ReportClasses property of your DbContxt object, It will fetch data from teh ReportClassRealTable table in your database.

Related

Map One-To-Many to 2 tables at the same time

I have 2 tables IncomingCheck and OutgoingCheck which contain many History items. To achieve this I've used inheritance and inherited 2 classes for incoming and outgoing histories.
public class IncomingCheck
{
[Key]
public int Id { get; set; }
public virtual IList<IncomingCheckHistory> History { get; set; }
//... other stuff
}
public class OutgoingCheck
{
[Key]
public int Id { get; set; }
public virtual IList<OutgoingCheckHistory> History { get; set; }
//... other stuff
}
public class CheckHistory
{
[Key]
public int Id { get; set; }
//... other stuff
}
public class IncomingCheckHistory : CheckHistory
{
public IncomingCheck IncomingCheck { get; set; }
}
public class OutgoingCheckHistory : CheckHistory
{
public OutgoingCheck OutgoingCheck { get; set; }
}
This approach works perfectly. In my database I have a table called CheckHistories with 2 nullable columns named [IncomingCheck_Id] and [OutgoingCheck_Id].
Now I have created a view on IncomingCheck which I created in Sql Server Management Studio and I can get its data using EF:
public class ViewIncomingCheck
{
[Key]
public int Id { get; set; }
public virtual IList<IncomingCheckHistory> History { get; set; }
//... other stuff
}
So far so good, but now I want Entity Framework to automatically load the History items but when I try to load the data, I get the following error:
SqlException: Invalid column name 'ViewIncomingCheck_Id'.
Invalid column name 'ViewIncomingCheck_Id'.
My guess is that the EF is looking for a column named ViewIncomingCheck_Id in the IncomingCheckHistory table but can't find it.
Is there a way to tell EF that it should use IncomingCheck_Id instead of ViewIncomingCheck_Id?

Entity Framework 6 - Code first - FK is generated in inherited classes but relation is defined in base class

What i want is to have a base class and two separate lists of inherited classes.
This is my model:
public class Instance
{
public int InstanceId { get; set; }
public virtual ICollection<User> Users { get; internal set; }
public virtual ICollection<MasterUser> MasterUsers { get; internal set; }
}
public abstract class CoreUser
{
[Key]
public int UserId { get; set; }
public int InstanceId { get; set; }
public virtual Instance Instance { get; set; }
}
[Table("Users")]
public class User : CoreUser
{
public string UserName { get; set; }
}
[Table("MasterUsers")]
public class MasterUser : CoreUser
{
public string MasterUserName { get; set; }
}
This is my DbContext:
public class MyContext : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<MasterUser> MasterUsers { get; set; }
public DbSet<Instance> Instances { get; set; }
}
This will create 4 tables with TPT inheritance model which is fine. The problem is Users and MasterUsers table will contain foreign key to Instance (it will be called Instance_InstanceId) which is redundant since this FK is defined in the CoreUser base class. These two FK columns are not even populated, they are always NULL, CoreUsers InstanceId column is populated when you add either User or MasterUser.
If I remove both referenced from Instance class like so:
public class Instance
{
public int InstanceId { get; set; }
}
Problem goes away but that also renders my application unusable.
I can also solve my problem like so:
public class Instance
{
public int InstanceId { get; set; }
public virtual ICollection<CoreUser> Users { get; internal set; }
}
And then iterate trough collection filtering out each type of user but this approach will lazy load all of the users even though I just want to iterate trough MasterUsers only.
One possible solution was to use TPC but in reality, CoreUser class will contain FKs to some other Classes which is not supported in TPC (only top level classes in hierarchy can contain FKs).
Is there any way I can get this to work in EF using two separate lists in Instance class and have them lazy loaded?
EDIT
Actually, the above code would work just fine. It will break if you introduce one more class that references CoreUser for example:
public class UserPolicy
{
public int PolicyId { get; set; }
public virtual CoreUser PolicyUser { get; internal set; }
}
Managed to get around this. Solution that I was able to use is to move relationship between CoreUser and Instance to User and MasterUser like so:
public class Instance
{
public int InstanceId { get; set; }
// Still referencing two lists
public virtual ICollection<User> Users { get; internal set; }
public virtual ICollection<MasterUser> MasterUsers { get; internal set; }
}
public abstract class CoreUser
{
[Key]
public int UserId { get; set; }
// No reference to instance. Works if you don't need it from CoreUser
}
[Table("Users")]
public class User : CoreUser
{
// FK to Instance defined in CoreUser
public int InstanceId { get; set; }
public virtual Instance Instance { get; set; }
public string UserName { get; set; }
}
[Table("MasterUsers")]
public class MasterUser : CoreUser
{
// FK to Instance defined in MasterUser
public int InstanceId { get; set; }
public virtual Instance Instance { get; set; }
public string MasterUserName { get; set; }
}

What is the best strategy of creating code first database with inherited entities?

For example if I have a model:
public class BasePolicy {
public int Id { get; set; }
public string Name { get; set; }
}
public class PaymentPolicy : BasePolicy {
public string PaymentMethod { get; set; }
}
public class ReturnPolicy : BasePolicy {
public int ReturnTerm { get; set; }
}
... and want to create codefirst database and a repository with next requirements:
ability to retrieve base entities by Id in base type (BasePolicy). This is necessary for admin index page which displays list of policies only by it's name.
I need to have access to children specific properties (PaymentMethod if it is PaymentPolicy - etc.) using select by Id . This is necessary for edit actions.
What is the best way to do that? Should I create seperate table for each child type?
public class Database : DbContext
{
public DbSet<PaymentPolicy> PaymentPolicies { get; set; }
public DbSet<ReturnPolicy> ReturnPolicies { get; set; }
}
+ data is logically sorted
- I will not be able to get BasePolicy entity by it's unique id without joining those tables and specifying policy type in select query. That's why I should inject some PolicyType enum to base type and implement repository method which will get BasePolicy by it's type (to determine which table to get from) and only then by unique Id - and downcast BasePolicy to specific child type policy. This is the solution I'm using just now.
... should I remove inheritance at all?
public class PaymentPolicy {
public int Id { get; set; }
public string Name { get; set; }
public string PaymentMethod { get; set; }
}
public class ReturnPolicy {
public int Id { get; set; }
public string Name { get; set; }
public int ReturnTerm { get; set; }
}
+ data is still logically sorted
- I still will not be able to get BasePolicy entity by it's unique id.
... should I add child types as navigation properties to base type?
public class BasePolicy {
public int Id { get; set; }
public string Name { get; set; }
public PaymentPolicy PaymentPolicy { get; set; }
public ReturnPolicy ReturnPolicy { get; set; }
}
public class PaymentPolicy {
public string PaymentMethod { get; set; }
}
public class ReturnPolicy {
public int ReturnTerm { get; set; }
}
- This will destroy logic model structure
+ I will be able to get list of policies without redundant joins
+ It will provide strong one to one relationship
Or are there some more advanced strategies and techniques?

Introducing FOREIGN KEY constraint 'FK_dbo.Models_dbo.Makes_MakeId' on table 'Models' may cause cycles or multiple cascade paths

This is my first day I've spent exploring ASP.NET MVC 4. Specifically I'm using the Web API and obviously this issue is actually an MS SQL issue. I'm running EF migrations PM> Update-Database to get this error, but have seen it when first creating the models. My models are:
public class Car
{
public int Id { get; set; }
public string Name { get; set; }
public int MakeId { get; set; }
public virtual Make Make { get; set; }
public int ModelId { get; set; }
public virtual Model Model { get; set; }
}
public class Make
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Model> Models { get; set; }
}
public class Model
{
public int Id { get; set; }
public string Name { get; set; }
public int MakeId { get; set; }
public virtual Make Make { get; set; }
}
The DB context is:
public class CarsContext : DbContext
{
public CarsContext() : base("name=CarsContext") { }
public DbSet<Car> Cars { get; set; }
public DbSet<Make> Makes { get; set; }
public DbSet<Model> Models { get; set; }
}
}
Would appreciate any help. My background is 5/6 solid of PHP and MySQL, so this is a steep learning curve.
Thanks.
Luke McGregor is correct. In addition to the way you fixed this you can override the default mapping that entity framework is giving you so that it doesn't cascade delete. In you CarsContext class you can override the OnModelCreating() method and specify your own mappings using fluent. This overrides what EF is trying to do by default. So you can do something like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Car>()
.HasOptional(x => x.Model)
.WithMany(y => y.Cars) //Add this property to model to make mapping work
.WillCascadeOnDelete(false);
}
This will still work with automatic migrations.
Hope that helps.

How to wrap a key with another object in entity framework / code first

I just started prototyping our existing object model in entity framework/code first and hit my first snag. Unfortunately the documentation for this seems to be very scarce.
My key is not a primitive but an object that wraps a primitive. How do I get this to work with EF/Code first:
public class EFCategoryIdentity
{
public string IdentityValue { get; private set; }
public EFCategoryIdentity(string value)
{
IdentityValue = value;
}
}
public class EFCategory
{
[Key]
public EFCategoryIdentity CategoryIdentity { get; set; }
public string Name { get; set; }
public virtual ICollection<EFProduct> Products { get; set; }
}
public class EFProduct
{
[Key]
public int ProductId { get; set; }
public string Name { get; set; }
public virtual EFCategory Category { get; set; }
}
What do I need to put here to make this work?
public class MyTestContext : DbContext
{
public DbSet<EFCategory> Categories { get; set; }
public DbSet<EFProduct> Products { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<EFCategory>()
.// Help!
}
}
Thanks!
Entity framework can use only primitive types as keys. Every time you wrap some mapped property to separate type you are creating complex type. Complex types have some limitation
They cannot be keys
They cannot contain keys
They cannot contain navigation properties
etc.

Categories