NullReferenceException on join with Postgres EF Provider - postgresql

I have a postgres database and using asp.net core mvc (+ ef). The database is created correctly. I have two tables 'Module' and 'ModuleMenu'. I want to get all the menu's for a given module but I keep on failing to create the linq query.
Situation
Model: Module.cs
namespace project.Model
{
public class Module
{
[Required]
public string ID { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Description { get; set; }
}
}
Model: ModuleMenu.cs
namespace project.Models
{
public class ModuleMenu
{
[Required]
public string ID { get; set; }
public int ModuleID { get; set; }
[Required]
public string Title { get; set; }
[ForeignKey("ModuleID")]
public virtual Module Module { get; set; }
}
}
ApplicationDbContext.cs
namespace project.Data
{
public class ApplicationDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
public DbSet<Module> Modules { get; set; }
public DbSet<ModuleMenu> ModuleMenus { get; set; }
}
}
Query
public List<ModuleMenu> GetModuleMenus(){
var query = from m in _dbContext.ModuleMenus
join mod in _dbContext.Modules on
m.ModuleID equals mod.ID
select m;
return query.ToList();
}
Error
fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[0]
An exception was thrown attempting to execute the error handler.
System.NullReferenceException: Object reference not set to an instance of an object.
Can anyone help me to correctly create the query?

Is this part correct in your code?
public int ModuleID { get; set; }
It seems that you might have had an error in the type used for the fk.
Below I changed the type to be string rather than int.
public string ModuleID { get; set; }
based on that update, the query could look like this.
public ModuleMenu[] GetModuleMenusForModule(string moduleId)
{
return _dbContext.ModuleMenus.Where(x => x.ModuleID == moduleId).ToArray();
}

I would expect that model to error (ModelID and ID are incompatible types). If that were correct, your code should work. Or simpler:
public List<ModuleMenu> GetModuleMenus()
{
return _dbContext.ModuleMenus.ToList();
}

Related

Invalid column name when using Entity Framework Core Table Per Hierarchy Inheritance

I am new to EF Core and am trying to use TPH Inheritance with Entity Framework Core
I have the following classes defined
public class WorkItem {
public Guid Id { get; set; }
public string WorkItemType { get; set; }
public string Description { get; set; }
}
public class Job : WorkItem {
public string BillingNotes { get; set; }
}
In my context, I have
public class JobContextNew : DbContext {
public virtual DbSet<WorkItem> WorkItem { get; set; }
public virtual DbSet<Job> Job { get; set; }
public JobContextNew(DbContextOptions<JobContextNew> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.Entity<WorkItem>(entity => entity.Property(e => e.Id).ValueGeneratedNever());
modelBuilder.Entity<WorkItem>()
.HasDiscriminator(workitem => workitem.WorkItemType)
.HasValue<Job>(nameof(Job));
}
}
If I omit the field in Job, it will pull the data just fine but when I add the BillngNotes back in I get the following error: Invalid column name 'BillingNotes
Can anyone tell me what I might be doing wrong?

Entity Framework fails to get child elements

I have SQLite db and these EF models and context.
Models and Context
public class CardHolder
{
public int CardHolderId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string PhoneNumber { get; set; }
public string EmailAddress { get; set; }
public string TenantName { get; set; }
public ICollection<AccessCard> AccessCards { get; set; }
}
public class AccessCard
{
public int AccessCardId { get; protected set; }
public CardHolder CardHolder { get; set; }
public DateTime ActivationDate { get; protected set; }
public bool ActivationProcessed { get; set; }
public DateTime? DeactivationDate { get; protected set; }
public string DeactivationReason { get; set; }
public bool DeactivationProcessed { get; set; }
}
public class MyContext : DbContext
{
public DbSet<CardHolder> CardHolders { get; set; }
public DbSet<AccessCard> AccessCards { get; set; }
}
And the Main program
class Program
{
static void Main(string[] args)
{
using (var db = new MyContext())
{
var cardHolders = db.CardHolders.Include("AccessCard").ToList();
}
}
}
Question1: Why do I get this exception
System.InvalidOperationException: 'A specified Include path is not
valid. The EntityType 'SQLiteDemo.Models.CardHolder' does not declare
a navigation property with the name 'AccessCard'.'
If I replace it with
var cardHolders = db.CardHolders.Include("AccessCards").ToList();
I get another error:
SQL logic error no such column: Extent2.CardHolder_CardHolderId
What is wrong with Entity Framework?
Question2: Why cant I use arrow function in Include statement, it doesnt compile at all?
var cardHolders = db.CardHolders.Include(x => x.AccessCards).ToList();
Question3: Why do I need to use Include at all if my ICollection association property AccessCards is NOT virtual - that means eager loading must work by itself!
Why the hell it is so problematic and buggy? Nothing works as it should :(
1 - You have a typo as you have already determined :)
1B - "SQL logic error no such column: Extent2.CardHolder_CardHolderId"
EF isn't finding your FK. You could add it to your AccessCard model:
public int CardHolderId { get; set; }
2 - You need to pull in the LINQ extensions. Make sure you have both of these using statements at the top:
using System.Data.Entity;
using System.Linq;
3 - You, like many others, are misunderstanding lazy loading. Eager loading still requires an Include() to fetch related data. Lazy loading only fetches the relations when you access them.

EF code first telling me to do the migration for db object which is already is in db

i am working with EF code first. so initially i have no tables in database. so i wrote some class and when query those class then i saw EF code first create those tables in db but when i create sql server view in db and later map that view with my code in c# & EF project and when i try to query that view then i was getting error message as follows.
Additional information: The model backing the 'TestDBContext' context has changed since the database was created. Consider using Code First Migrations to update the database
i understand that EF is telling me to do the migration but if i migrate then EF will create that view in db again when the view is in db already exist.
so tell me how could i inform EF that my view is already is in db so migration is not required.
please guide me. thanks
EDIT 1
first time my database has no table. so i wrote some classes like below one.
public class CustomerBase
{
public int CustomerID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string Phone { get; set; }
public string Fax { get; set; }
}
public class Customer : CustomerBase
{
public virtual List<Addresses> Addresses { get; set; }
}
public class Addresses
{
[Key]
public int AddressID { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public bool IsDefault { get; set; }
public virtual List<Contacts> Contacts { get; set; }
public int CustomerID { get; set; }
public virtual Customer Customer { get; set; }
}
public class Contacts
{
[Key]
public int ContactID { get; set; }
public string Phone { get; set; }
public string Fax { get; set; }
public bool IsDefault { get; set; }
public int AddressID { get; set; }
public virtual Addresses Customer { get; set; }
}
public class TestDBContext : DbContext
{
public TestDBContext()
: base("name=TestDBContext")
{
}
public DbSet<Customer> Customer { get; set; }
public DbSet<Addresses> Addresses { get; set; }
public DbSet<Contacts> Contacts { get; set; }
}
when i query the customer like below query then EF create all required tables in db behind the curtains.
var bsCustomer = (from cu in db.Customer
where (cu.CustomerID == 2)
select new
{
cu,
Addresses = from ad in cu.Addresses
where (ad.IsDefault == true)
from ct in ad.Contacts
select ad,
}).ToList();
later i create a view in db and refer that view in code like below one.
public partial class vwCustomer
{
[Key]
public int CustomerID { get; set; }
public string FirstName { get; set; }
}
public class vwCustomerConfiguration : EntityTypeConfiguration<vwCustomer>
{
public vwCustomerConfiguration()
{
this.HasKey(t => t.CustomerID);
this.ToTable("vwCustomers");
}
}
so now my DbContext look like below one with view class reference
public class TestDBContext : DbContext
{
public TestDBContext()
: base("name=TestDBContext")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new vwCustomerConfiguration());
}
public DbSet<Customer> Customer { get; set; }
public DbSet<Addresses> Addresses { get; set; }
public DbSet<Contacts> Contacts { get; set; }
public virtual DbSet<vwCustomer> vwCustomers { get; set; }
}
Error occur the moment i try to query the view
using (var db = new TestDBContext())
{
var listMyViews = db.vwCustomers.ToList();
}
the error was Additional information: The model backing the 'TestDBContext' context has changed since the database was created. Consider using Code First Migrations to update the database
thanks
Another way we can do it and it solve my problem. see the code.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer<YourDbContext>(null);
base.OnModelCreating(modelBuilder);
}
code taken from here https://stackoverflow.com/a/6143116/6188148
we can follow this approach too.
public partial class AddingvwCustomer : DbMigration
{
public override void Up()
{
}
public override void Down()
{
}
}
i guess this will works too but not tested myself.
we can use the Fluent API to configure it using the Ignore method:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Ignore<MyClass>();
}
Add new migration as normally and from the migration code in Up (and Down) method remove code that tries to create new table manually (call to CreateTable method in Up and DropTable in Down). Then apply migration to your db and everything works perfectly.
Unfortunately automatic migration generation is not very intelligent tool and very often one need to manually specify how the database should be altered. In the documentation for EF migrations it is stated that it is perfectly fine to edit manually migrations code.

Entity Framework Navigation Property Error

I am getting this error in my .Net MVC 4 web application:
The property 'Username' cannot be configured as a navigation property. The
property must be a valid entity type and the property should have a non-abstract
getter and setter. For collection properties the type must implement
ICollection<T> where T is a valid entity type.
I am very new to Entity Framework and I can't seem to get around this issue. Here is some code:
//DB Context
public class EFDbContext : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Role> Roles { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().HasMany(u => u.Roles).WithMany(r => r.Users).Map(x => x.MapLeftKey("Username").MapRightKey("RoleName").ToTable("Users_Roles"));
}
}
//Entity Classes
public class User
{
[Key]
public string Username { get; set; }
public string Password { get; set; }
public string Email { get; set; }
public string Comment { get; set; }
public int Level { get; set; }
public string PasswordQuestion { get; set; }
public string PasswordAnswer { get; set; }
public bool IsApproved { get; set; }
public DateTime LastActivityDate { get; set; }
public DateTime LastLoginDate { get; set; }
public DateTime LastPasswordChangedDate { get; set; }
public DateTime CreationDate { get; set; }
public bool IsOnLine { get; set; }
public bool IsLockedOut { get; set; }
public DateTime LastLockedOutDate { get; set; }
public int FailedPasswordAttemptCount { get; set; }
public DateTime FailedPasswordAttemptWindowStart { get; set; }
public int FailedPasswordAnswerAttemptCount { get; set; }
public DateTime FailedPasswordAnswerAttemptWindowStart { get; set; }
[InverseProperty("RoleName")]
public virtual ICollection<Role> Roles { get; set; }
public override string ToString()
{
return this.Username;
}
}
public class Role
{
[Key]
public string RoleName { get; set; }
public int Level { get; set; }
[InverseProperty("Username")]
public virtual ICollection<User> Users { get; set; }
public override string ToString()
{
return this.RoleName;
}
}
//Repository
public class EFUsersRepository : IUsersRepository
{
private EFDbContext context = new EFDbContext();
public IQueryable<User> Users
{
get { return context.Users; }
}
public User GetUser(string username)
{
return context.Users.Find(username); //THIS IS WHERE THE CRASH OCCURS
}
}
//DB Setup
Table Users, Role and Users_Role. Users_Role is a simple linking table with [username, role] columns both of type varchar.
The database tables columns & types match the two classes above (User,Role).
I inherited this project which was unfinished but I can't get it to run successfully. Any help understanding what the issue is would be helpful. Thanks!
It might be that Entity Framework is updated. Easiest way will be to recreate the DataModel.
Even if the previous programmer did not use Entity Data Mode, you can at least copy the auto generated code such as EFDbContext, Users and Roles classes.
It turns out, after commenting out enough items all day long, the the following lines are what caused this error for me:
[InverseProperty("RoleName")] //In file User.cs (as shown above)
[InverseProperty("UserName")] //in file Role.cs (as shown above)
I am still learning Entity Framework and I don't know why this was the solution, but it stopped the error which I reported above.
I hope that this helps someone else and if anyone wants to help me understand what the issue was in detail, please feel free. I am eager to learn.

EF 4.1 code first still looking for old table that no longer exists

I am using Entity Framework 4.1 code first.
I had a table in the database with the name MaritalStatus. I deleted it and created a new table in its place called MaritalStatuses. Whenever I try to get all the records from the table I get an error:
Invalid object name 'dbo.MaritalStatus'.
The query that it is trying to execute is:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
[Extent1].[IsActive] AS [IsActive]
FROM [dbo].[MaritalStatus] AS [Extent1]}
Why would it still be looking for table MaritalStatus that I deleted? Can it be possible that it is cached somewhere? I dropped the whole database and recreated it via scripts. Still no luck. Maybe it has an issue when it comes to the "es" part of the name?
Context class:
public class HefContext : DbContext
{
public DbSet<Bank> Banks { get; set; }
public DbSet<AccountType> AccountTypes { get; set; }
public DbSet<MaritalStatus> MaritalStatuses { get; set; }
}
View model (with partial properties):
public class EditGrantApplicationViewModel
{
public int Id { get; set; }
public string EmployeeNumber { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int MaritalStatusId { get; set; }
public IEnumerable<MaritalStatus> MaritalStatuses { get; set; }
public int BankId { get; set; }
public IEnumerable<Bank> Banks { get; set; }
public int AccountTypeId { get; set; }
public IEnumerable<AccountType> AccountTypes { get; set; }
}
Dropdown list in view for MaritalStatuses:
<td><label>Marital Status:</label> <span class="red">**</span></td>
<td>
#Html.DropDownListFor(x => x.MaritalStatusId, new SelectList(Model.MaritalStatuses, "Id", "Name", Model.MaritalStatusId), "-- Select --")
#Html.ValidationMessageFor(x => x.MaritalStatusId)
</td>
Controller:
public ActionResult Create()
{
EditGrantApplicationViewModel viewModel = new EditGrantApplicationViewModel
{
MaritalStatuses = maritalStatusService.GetAll(),
Banks = bankService.GetAll(),
AccountTypes = accountTypeService.GetAll()
};
return View(viewModel);
}
Service:
public IEnumerable<MaritalStatus> GetAll()
{
return maritalStatusRepository.GetAll();
}
Repository:
HefContext db = new HefContext();
public IEnumerable<MaritalStatus> GetAll()
{
return db.MaritalStatuses;
}
Model class:
public class MaritalStatus
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
}
You may have renamed the table in your database, but your Model class is still tied to the old name. You need to map the entity to the desired table name in the OnModelCreating method of your DbContext object
public class HefContext : DbContext
{
public DbSet<Bank> Banks { get; set; }
public DbSet<AccountType> AccountTypes { get; set; }
public DbSet<MaritalStatus> MaritalStatuses { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<MaritalStatus>().ToTable("MaritalStatuses");
}
}
Update:
Apparently EF code first has some issues with the pluralization of some table names, such as Status. Out of curiosity I tested a few others and found several which also had this same issue.
I guess this is wrong:
public DbSet<MaritalStatus> MaritalStatuses { get; set; }
Should be:
public DbSet<MaritalStatuses> MaritalStatuses { get; set; }