Entity Framework core 2.0 HasColumnType throw run time exception - entity-framework-core

I have a custom enum type EmployementState (complex type in EF 6 term, I think)
in OnModelCreating, the following code throw an run time exception.
modelBuilder.Entity<Employee>().Property(e => e.EmployementState.Value).HasColumnType("int");
The exception show below:
Message=The expression 'e => e.EmployementState.Value' is not a valid property expression. The expression should represent a property access: 't => t.MyProperty'.
cannot figure out how to get the syntax right or is there are something else I was missing?
Thank you for your help.

Assuming you have the following model for your EmployementState object that will hold the different states for your employee:
public class EmployementState
{
public int Id { get; set; }
public string Name { get; set; }
}
You can then add a reference like:
public class Employee
{
public int Id { get; set; }
public string FirstName { get; set; }
// All your user properties here
public int EmployementStateId { get; set; }
public virtual EmployementState EmployementState { get; set; }
}
I recommend this because is the best approach when you are working with states describing your objects.
Of course being two separate models they are configurable so configurations like this one below are easy to implement.
modelBuilder.Entity<Employee>().Property(e => e.EmployementStateId)
.HasColumnName("employement_state_ID");

Related

One-to-Many EF .NET Core Relationship Not Working

I have a .net core api application which includes EF to retrieve data. I have set up a data context and I can map tables from the db fine. When I try and set up a relationship though I am always getting a null back for the nested object.
I have an 'Opportunity' class which contains an ICollection of 'Notes'
public class Opportunity
{
public int Id { get; set; }
public string Name { get; set; }
...
public decimal FinalDealProfit { get; set; }
public ICollection<CRMNote> CRMNotes { get; set; }
}
and a Note class that references the opportunity:
public class CRMNote
{
public int Id { get; set; }
public int OpportunityId { get; set; }
public string Note { get; set; }
public string User { get; set; }
public DateTime DateTime { get; set; }
public string FilePath { get; set; }
public Opportunity Opportunity { get; set; }
}
In my context class have the following set up:
modelBuilder.Entity<Opportunity>(entity =>
{
entity.ToTable("CRM_Opportunity");
entity.HasMany<CRMNote>(n => n.CRMNotes)
.WithOne(t => t.Opportunity)
.HasForeignKey(k => k.OpportunityId);
});
and I have also been mapping the Note class:
modelBuilder.Entity<CRMNote>(entity =>
{
entity.ToTable("CRM_Note");
//entity.HasOne<Opportunity>(t => t.Opportunity)
// .WithMany(p => p.CRMNotes)
// .HasForeignKey(k => k.OpportunityId);
});
as you can see I have been playing around with how to connect the entities together.
Whenever I retrieve the opportunity though the notes array is always null. I have tried putting an empty constructor on the Opportunity class:
public Opportunity()
{
CRMNotes = new List<CRMNote>();
}
but this just means I get an empty array rather than a null.
I can't see what I have missed. I have checked the docs for it:
https://www.entityframeworktutorial.net/efcore/one-to-many-conventions-entity-framework-core.aspx
but clearly I have missed something. Any help greatly appreciated as this should be an easy task but something is clearly eluding me.
There are three common O/RM patterns used to load related data
Eager loading,
Explicit loading
and
Lazy loading
For example, in eager loading you can use:
var opportunities=context.opportunities.Include(opportunity=>opportunity.CRMNotes).ToList()

Entity-Framework-Core: Mapping 1 to 1 Relationships using Composite Keys

I'm having difficult configuring a 1:1 mapping in EntityFrameworkCore using FluentAPI. The navigational reference is always NULL. The only obvious difference between my code and countless others I have examined is I am trying to map via composite keys.
I've played around using annotations instead of Fluent API but encounter the same issue described in my summary.
Class Definitions
[Table("SomeTable")]
public class Defect
{
[Column("Record")]
public int DefectId { get; set; }
[Column("insp_id")]
public int InspId { get; set; }
[Column("defectnum")]
public int Number { get; set; }
public virtual Simulation Simulation { get; set; }
}
[Table("SomeSimulationTable")]
public class Simulation
{
[Column("Record"), Key]
public int SimTableId { get; set; }
[Column("insp_id")]
public int InspId { get; set; }
[Column("DefectNumber")]
public int Number { get; set; }
[Column("SimulationName")]
public string Name{ get; set; }
[Column("SimulationAlgorithm")]
public string Algorithm{ get; set; }
public virtual Defect Defect { get; set; }
}
Fluent API (in OnModelCreating)
modelBuilder.Entity<Defect>()
.HasKey(h => new { h.InspId , h.Number });
modelBuilder.Entity<Defect>()
.HasOne<Simulation>(p => p.Simulation)
.WithOne(i => i.Defect)
.HasForeignKey<Simulation>(b => new { b.InspId , b.Number });
When the "Defect" class is populated through the dbContext all data is available; however, when I attempt to access the "Simulation" property of the "Defect" class I encounter the following error:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
I have also verified there is valid data in our database where the "Defect" should have a "Simulation".
Any help? Throwing myself at the mercy of other coders....
Take a look at the Include method when loading from the database, it will be null unless you explicitly load:
https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.entityframeworkqueryableextensions.include?view=efcore-2.1
https://entityframeworkcore.com/querying-data-include-theninclude

Entity Framework and RESTful WebAPI - possible circular reference

Here is a simplified version of my model:
public class User {
public int UserID { get; set; }
public string FirstName { get; set; }
public virtual ICollection<Recipe> Recipes { get; set; }
}
public class Recipe {
public int RecipeID { get; set; }
public string RecipeName { get; set; }
public int UserID { get; set; }
public virtual User User { get; set; }
}
I have a controller that I'd like to return a User as well as some summary information about their recipes. The scaffolded controller code looks like this:
var user = await _context.Users.SingleOrDefaultAsync(m => m.UserID == id);
It works fine. Now I try to add the Recipes, and it breaks:
var user = await _context.Users.Include(u => u.Recipes).SingleOrDefaultAsync(m => m.UserID == id);
My web browser starts to render the JSON, and it flickers and I get a message in the browser saying the connection has been reset.
My Theory - I believe that the parent (User) renders, which exposes the child (Recipe) which contains a reference to the parent (User), which contains a collection of the child (Recipe) and so on which is causing an infinite loop. Here's why I think this is happening:
The Visual Studio debugger allows me to navigate the properties in that way infinitely.
If I comment out the Recipe.User property, it works fine.
What I've tried
I tried to just include the data from Recipe that I need using Entity Framework projection (I'm attempting to not include Recipe.User). I tried to only include Recipe.RecipeName... but when I try to use projection to create an anonymous type like this:
var user = await _context.Users.Include(u => u.Recipes.Select(r => new { r.RecipeName })).SingleOrDefaultAsync(m => m.UserID == id);
I receive this error:
InvalidOperationException: The property expression 'u => {from Recipe r in u.Recipes select new <>f__AnonymousType1`1(RecipeName = [r].RecipeName)}' is not valid. The expression should represent a property access: 't => t.MyProperty'.
What is the solution? Can I project with different syntax? Am I going about this all wrong?
Consider using POCOs for serialization rather than doubly-linked entity classes:
public class UserPOCO {
public int UserID { get; set; }
public string FirstName { get; set; }
public ICollection<RecipePOCO> Recipes { get; set; }
}
public class RecipePOCO {
public int RecipeID { get; set; }
public string RecipeName { get; set; }
public int UserID { get; set; }
}
Copy the entity contents to the corresponding POCO and then return those POCO objects as the JSON result. The removal of the User property via usage of the RecipePOCO class will remove the circular reference.
I can propose you 3 options.
U sing [JsonIgnore] on property, but it will work on every use of Recipe class, so when you would like to just return Recipe class you won't have User in it.
public class Recipe {
public int RecipeID { get; set; }
public string RecipeName { get; set; }
public int UserID { get; set; }
[JsonIgnore]
public virtual User User { get; set; }
}
You can this solution to stop reference loop in all jsons https://stackoverflow.com/a/42522643/3355459
Last option is to create class (ViewModel) that will only have properties that you want send to the browser, and map your result to it. It is propably best from security reason.

Popcorn API: How to enable expansion on a custom translation?

I'm using Popcorn to allow clients of my API to specify how deeply to unravel the properties of the requested object.
I'm having trouble mapping one of my data model entities to a projection. All the entities are entity framework data models so I'm using 'MapEntityFramework' where I can.
The data model looks like this:
public class DataModel {
public List<Person> Persons { get; set; }
}
public class Person {
public Guid Id { get; set; }
public List<Pet> Pets {get; set;}
public List<Pet> GetLivingPets() {
// Do some computation to get the pets that are alive
}
}
public class Pet {
public Guid Id { get; set; }
public string Name { get; set; }
public bool Alive { get; set; }
}
public PetProjection {
public Guid? Id { get; set; }
public string Name { get; set; }
}
public PersonProjection {
public Guid? Id { get; set; }
public List<PetProjection> LivingPets {get; set;}
}
The request I'd like my clients to be able to make requests that specify the nesting of the dynamically generated list.
http://localhost:5000/api/1/Persons?include=[Id,LivingPets[Name]]
Which would return a list like this:
[
{
"Id": "00000000-0000-0000-0000-000000000000",
"LivingPets": [
{
"Name": "Capt Meowmix"
}
]
}
]
This is the mapping that I am attempting:
popcornConfig
.Map<Person, PersonProjection>(config: (personConfig) =>
{
personConfig.Translate(fp => fp.LivingPets, f => f.GetLivingPets()?.ToList()); // Error: 'Dictionary<string, object>' does not contain a definition for 'GetLivingPets' and no extension method 'GetLivingPets' accepting a first argument of type 'Dictionary<string, object>' could be found (are you missing a using directive or an assembly reference?)
})
.MapEntityFramework<Pet, PetProjection, DataModel>(dbContextOptionsBuilder);
What do I need to do to write a mapping that would make use of another mapping I've already defined? Is this something that can be done with the library? Am I missing something?
There's no need for the Translate on LivingPets. Popcorn automatically looks for same named properties between the mapped entity and its projection. It'll look for matching properties, or failing that matching methods that require no parameters, so if you name your method LivingPets it'll automatically work. However, what you're doing with the Translate should also work.
Regarding the translate function, as long as it returns an object Popcorn has a mapping for, the client should be able to expand it. You were seeing that error because the compiler was picking the wrong version of the Translate function. If you switch
personConfig.Translate(fp => fp.LivingPets, f => f.GetLivingPets()?.ToList());
to
personConfig.Translate(fp => fp.LivingPets, (f,c) => f.GetLivingPets()));
The compilation error should disappear. This is a bug and is being tracked in this issue.

Value cannot be null. Parameter name: entitySet

I have a fairly standard setup with simply POCO classes
public class Project
{
public int ProjectId { get; set; }
public string Name { get; set; }
public int? ClientId { get; set; }
public virtual Client Clients { get; set; }
}
They use an interface
public interface IProjectRepository
{
IEnumerable<Project> Projects { get; }
}
and are constructed as a repository for ninject to bind to
public class EFProjectRepository : IProjectRepository
{
private EFDbContext context = new EFDbContext();
public IEnumerable<Project> Projects
{
get { return context.Projects; }
}
}
The actual context is a simply DbContext
public class EFDbContext : DbContext
{
public DbSet<Project> Projects { get; set; }
}
When I try and enable code first migrations I get the following error
I have done this exact process with other projects and there as never been an error. This is connecting to a local Sql Server Database. There does not seem to be a problem with the connection string. I have searched for this error online but the solutions seem to answer questions that do not directly relate to my setup.
I had the same issue and the cause was a POCO class that had a property of type Type.
Late to the game...but if it helps...
I had this same problem, everything was working fine, but this issue appeared, I added the following to one of my classes
public HttpPostedFileBase File { get; set; }
which seemed to break it.
I ensured I didn't map this to the database by using the following:
[NotMapped]
public HttpPostedFileBase File { get; set; }
You need to add the following using statement:
using System.ComponentModel.DataAnnotations.Schema;
Hope this helps
This problem can occur if one of the POCO classes was not declared in the DbContext.
I added them and the error went away
I had changed the name of the Task POCO class because of its association with a built in .NET name System.Threading.Tasks. However I had not changed this in the "TaskTimeLog" POCO where there was a relation. When going through the code the "Task" property in the "TaskTimeLog" POCO was not showing an error because it was now attached to that threading keyword and the reason I had changed the name in the first place.
I got this error:
Value cannot be null. Parameter name: entitySet
Turns out I was trying to join data from 2 different DbContexts.
var roles = await _identityDbContext.Roles
.AsNoTracking()
.Take(1000)
.Join(_configurationDbContext.Clients.ToList(),
a => a.ClientId,
b => b.Id,
(a,b) => new {Role = a, Client = b})
.OrderBy(x => x.Role.ClientId).ThenBy(x => x.Role.Name)
.Select(x => new RoleViewModel
{
Id = x.Role.Id,
Name = x.Role.Name,
ClientId = x.Role.ClientId,
ClientName = x.Client.ClientName
})
.ToListAsync();
The fix is to add ToList as shown. Then the join will happen in code instead of the database.
Only do this if you are OK with retrieving the whole table. (I know my "Clients" table will always be relatively small.)
For anyone not finding a resolution in the other answers, I got this error when I created a derived class from a class that had an instance in some model. The exception occurred on the first usage of my context in a request.
This is a stripped-down example that will reproduce the behaviour. Model is a DbSet in my context.
public class Model
{
public int Id { get; set; }
public Duration ExposureDuration { get; set; }
}
public class Duration
{
public int Value { get; set; }
public string Unit { get; set; }
}
//Adding this will cause the exception to occur.
public class DurationExtended : Duration
{ }
This happened during work in progress. When I changed the model property ExposureDuration to type DurationExtended, all was working again.
I had the same issue and it took quite a while to find out the solution.
In our case, we created a seperated project to handle the Entities and even if the default project in the Package Manager Console was the one handling the Entities, I need to set this project as the default project in order to make it work.
I hope this will help somebody else.
I got this error when I declared a variable of type Type - which is probably because is a complex type not supported by the DB.
When I changed it to string, the error went away
public class Sample
{
public int SampleID {get;set;}
public Type TypeInfo {get; set;} //This caused the error,
//because Type is not directly convertible
//in to a SQL datatype
}
I encountered this same issue and resolved like so:
Error in model class:
public class UserInformation
{
public string ID { get; set; }
public string AccountUserName { get; set; }
public HttpPostedFileBase ProfilePic { get; set; }
}
No error in model class
public class UserInformation
{
public string ID { get; set; }
public string AccountUserName { get; set; }
public string ProfilePicName { get; set; }
}
My issue was resolved once i updated the ProfilePic property type from HttpPostedFileBase to string. If you have a property that is not of type string, int, double or some other basic/standard type either replace such property or update to a type which SQL is more likely to accept.
Remove the line <Generator>EntityModelCodeGenerator</Generator> from your project file.
Check out this https://www.c-sharpcorner.com/UploadFile/5d065a/poco-classes-in-entity-framework/
I have some properties in "ExpenseModel", one of this was...
public virtual Type TypeId {get; set;}
which was causes the above same error because of "Type" propertyType,
so I changed "Type" => "ExpenseType" and it worked... :-)
public virtual ExpenseType TypeId {get; set;}
ExpenseModel.cs
public class ExpenseTypes
{
[Key]
public int Id { get; set; }
public string TypeName { get; set; }
public string Description { get; set; }
}
In my case I had to reference another model class called IanaTimeZone, but instead of
public virtual IanaTimeZone Timezone { get; set; }
out of rush I typed this:
public virtual TimeZone Timezone { get; set; }
and it compiled fine because VS thought it was System.TimeZone but EF6 was throwing the error. Stupid thing but took me a while to figure out, so maybe this will help someone.
To anyone else this might be helpful, I had a property TimeZone (the actual .NET TimeZone object) and this gave me the exact same error, not sure why but will dig deeper :)