Entity Framework Core 2.0 - Error Migration "Field of entity type is readonly and so cannot be set" - entity-framework-core

There might be something wrong in my model that I cannot figure out since I get the following error when trying to make a migration:
"An error occurred while calling method 'BuildWebHost' on class Program. Continuing without the application service provider. Error: Field 'k__BackingField' of entity type 'MapeoArticuloProveedor' is readonly and so cannot be set.
Unable to create an object of type 'NSideoContext'. Add an implementation of 'IDesignTimeDbContextFactory' to the project, or see https://go.microsoft.com/fwlink/?linkid=851728 for additional patterns supported at design time."
Entities:
[Table("MapeosArticuloProveedor", Schema = "public")]
public class MapeoArticuloProveedor
{
public string Codigo { get; set; }
public int? IdLadoDeMontaje { get; set; }
[ForeignKey("IdLadoDeMontaje")]
public virtual LadoDeMontajeMapeoArticulo LadoDeMontaje { get; }
}
[Table("LadosDeMontajeMapeosArticulos", Schema = "public")]
public class LadoDeMontajeMapeoArticulo
{
public string Codigo { get; set; }
public string Valor { get; set; }
}
What could it be?

#WanneBDeveloper basically you're exposing the property since you made it public. A more conservative approach would be to set it as follows:
public LadoDeMontajeMapeoArticulo LadoDeMontaje { get; private set; }
note the private keyword
Then the propery can only be set from within the class and not outside of it. Therefore you'll know which class is mutating it's state.

this is your issue:
public virtual LadoDeMontajeMapeoArticulo LadoDeMontaje { get; }
Basically the error is saying you can't set the "LadoDeMontaje" once it is retrieved.
Simply change it to:
public virtual LadoDeMontajeMapeoArticulo LadoDeMontaje { get; set; }

Related

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

Using OData with model inheritance cause missing property error

I got this error in my OData with asp.net core implementation during the runtime :The EDM instance of type '[XXX.Asset Nullable=True]' is missing the property 'externalId'.
The problem appear when I try to access the odata endpoint with the expand query: "/odata/v1/precinct?$expand=assets". It seems happening because I put the "ExternalId" property in my base class, its not happening if I put that property in the "Asset".
Below is my recent codes:
public abstract class Entity
{
public int Id { get; set; }
public string ExternalId { get; set; }
}
public class Precinct : Entity
{
public string Name { get; set; }
public string Description { get; set; }
public virtual IEnumerable<Asset> Assets { get; set; }
}
public class Asset : Entity
{
public string Name { get; set; }
public string Description { get; set; }
}
and here is my model configuration for ODATA
public class AssetModelConfiguration : IModelConfiguration
{
public void Apply(ODataModelBuilder builder, ApiVersion apiVersion)
{
var org = builder.EntitySet<Asset>("asset").EntityType;
org.HasKey(x => x.ExternalId);
org.Ignore(x => x.Id);
}
}
The strange thing is if I put that ExternalId in "Asset" class, it is working. Id property is the primary key while the "ExternalId" is marked as AlternateKey in the DBModel configuration.
am I missing something in my odata configuration? already tried many things but couldn't find a good answer. Any help would be appreciated!

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 :)

Entity Framework Code First and CA2227 "Collection Properties should be read only"

A one-many or many-many relationship in Entity Framework Code First looks like this:-
public class Foo
{
public int Id { get; set; }
public virtual ICollection<Bar> Bars { get; set; }
}
This violates Code Analysis rule 2227 "Collection Properties should be read only".
Making the setter protected doesn't help, and making it private:-
public class Foo
{
public int Id { get; set; }
public virtual ICollection<Bar> Bars { get; private set; }
}
then of course violates CA1811 "Foo.Bars.set(ICollection<Bar>) appears to have no upstream public or protected callers".
I'd rather not turn the rule off globally because the situation it exists to prevent is fairly important, but suppressing it locally every time I want to declare a relationship seems off. Is there a way to declare the relationship that doesn't violate CA2227?
Change your code to the following:
public class Foo {
public Foo() {
Bars = new Collection<Bar>();
}
public int Id { get; set; }
public virtual ICollection<Bar> Bars { get; private set; }
}
Place all your code first entities in their own assembly and exclude the rule for that assembly.

Update Model From Database (Database First)

I'm using MVC3 VS2010 with EF4.1, I have created my DB using SQL Server and I import it to the MVC3 Web Application.
I have a challenge here, when I come to Update Model from Database I do lost all my models files modifications, for example if I'm using attributes in some models for validation or so all that is overwritten with the new model properties.
Is there anyway to Update Model from Database without losing models' information?
OR
where should I define validation on my models instead of using the models' files directly?
Update: As this is still relatively popular, I have created a blog post on this.
http://jnye.co/Posts/19/adding-validation-to-models-created-by-entity-framework-database-first-c
If you want to validate your models, and not use viewModels, use partial classes to define validation attributes. For example:
Say you have a model like
public class User {
public string Name { get; set; }
}
If you wanted to put a string length validator on it you would need to create a partial class and utilise the MetadataTypeAttribute (this lives in System.ComponentModel.DataAnnotations)
The following classes should be defined in their own separate file, NOT put in the same file as your auto generated models.
[MetadataTypeAttribute(typeof(UserMetadata))]
public partial class User {
}
You then define your validation in the UserMetadata class as follows
public class UserMetadata{
[StringLength(50)]
public string Name {get; set;}
}
EDIT
I just found this article which explains the solution in a little more detail
http://themonitoringguy.com/tips-tricks/validating-microsoft-entity-framework-objects-c-mvc/
No, the files will be regenerated every time.
All the classes are defined as partial so you can easily add DataAnnotations using the MetadataTypeAttribute.
Let's say you have a User class defined as follow:
public partial class User {
public string Name {get;set;}
}
Create a IUser interface
public interface IUser {
[Required]
[DisplayName("User name")]
string Name {get;set;}
}
And then extend the User class to specify that IUser will be used as metadata.
[MetadataType(typeof(IUser))]
public partial class User {} //Empty class body
The first rule of any designer is: It it generates any code you can't modify it because it will be completely deleted next time you update anything in the designer.
All generated classes are partial so you can create your own partial part and put your custom logic there. You obviously can't add attributes to properties defined in auto generated part. In case of data annotations it is possible either through buddy classes or by custom T4 template which will contain your own logic to decide which data annotation should be added during code generation. Both scenarios are mostly considered as a bad practice because you should have separate view model per view with validation needed exactly for that view.
Check the namespace of the MainClass is same as Partial, and have the same Attributes. That is my solution.
example:
Metadata: Create this everywhere u want
public class FormMetadata
{
public int Id { get; set; }
public string Description { get; set; }
public Nullable<bool> IsEnable { get; set; }
public Nullable<System.DateTime> CreationDate { get; set; }
public int CompanieId { get; set; }
public string RegularExpression { get; set; }
public virtual ICollection<Field> Fields { get; set; }
[JsonIgnore]
public virtual Company Company { get; set; }
}
MainClass
namespace Transactions.Model
{
public partial class Form
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Form()
{
this.Fields = new HashSet<Field>();
}
public int Id { get; set; }
public string Description { get; set; }
public Nullable<bool> IsEnable { get; set; }
public Nullable<System.DateTime> CreationDate { get; set; }
public int CompanieId { get; set; }
public string RegularExpression { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Field> Fields { get; set; }
public virtual Company Company { get; set; }
}
}
Partial To Use the MetadataType
namespace Transactions.Model
{
[MetadataTypeAttribute(typeof(FormMetadata))]
public partial class Form
{
}
}
If you have problems to Create a Class Partial in the same NameSpace? Don't worry:
Create a Folder
Create the Class Partial in this folder
Change Namespace at the same of MainClass