I am using Entity Framwwork and Code First and getting really confused. I have this class:
public class Blocks
{
[Display(Name = "ID"),Required(ErrorMessage = "ID is required")]
[Key,HiddenInput(DisplayValue=false)]
public int BlockId { get;set; }
[Display(Name = "Blocked By"),Required(ErrorMessage = "Blocked By is required")]
public int ProfileId { get;set; }
[Display(Name = "Blocked"),Required(ErrorMessage = "Blocked is required")]
public int ProfileBlockedId { get;set; }
[Display(Name = "Date Blocked"),Required(ErrorMessage = "Date Blocked is required")]
public DateTime BlockDateTime { get;set; }
[Display(Name = "Block Reason")] public string BlockReason { get;set; }
public virtual Profiles Profile { get; set; }
public virtual Profiles ProfileBlocked { get; set; }
}
The profile class is more or less the same and that adds fine and has the correct SQL, but when I run /Blocks I get this error:
MySql.Data.MySqlClient.MySqlException (0x80004005): Unknown column 'Extent1.Profile_ProfileId' in 'field list'
at MySql.Data.MySqlClient.MySqlStream.ReadPacket()
at MySql.Data.MySqlClient.NativeDriver.GetResult(Int32& affectedRow, Int32& insertedId)
at MySql.Data.MySqlClient.Driver.GetResult(Int32 statementId, Int32& affectedRows, Int32& insertedId)
at MySql.Data.MySqlClient.Driver.NextResult(Int32 statementId)
at MySql.Data.MySqlClient.MySqlDataReader.NextResult()
at MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior behavior)
at MySql.Data.Entity.EFMySqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
at System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior)
at System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior)
this is because the sql produced is:
SELECT
`Extent1`.`BlockId`,
`Extent1`.`ProfileId`,
`Extent1`.`ProfileBlockedId`,
`Extent1`.`BlockDateTime`,
`Extent1`.`BlockReason`,
`Extent1`.`Profile_ProfileId`,
`Extent1`.`ProfileBlocked_ProfileId`
FROM `Blocks` AS `Extent1`
Notice the Profile_ and ProfileBlocked_. I have them virtual so I have a dropdown of profiles when adding or editing or have the profile name when shown on a list. The strange thing is the other tables. Everything has worked fine except for this one.
Here is the code that creates the wrong SQL and breaks:
//
// GET: /Blocks/
public ViewResult Index()
{
try {
return View(context.Blocks.Include(blocks => blocks.Profile).Include(blocks => blocks.ProfileBlocked).ToList());
}
catch (Exception ex)
{
ModelState.AddModelError("",ex.Message);
CompileAndSendError(ex);
return View(context.Blocks.ToList());
}
}
I am using:
ASP.net MVC 3
Razor Templates
Entity Framework
MVC Scaffolding [custom T4 ]
Give EF a little hint what are your Foreign Key properties by putting annotations on the properties:
...
[ForeignKey("Profile")]
public int ProfileId { get;set; }
...
[ForeignKey("ProfileBlocked")]
public int ProfileBlockedId { get;set; }
...
I believe that this is always necessary when you have more than one navigation property referencing to the same target class. The conventions don't detect in this case which properties could be the foreign keys - and EF creates their own FK column names (the Profile_ and ProfileBlocked_ things). And because the column names in the DB are different you get the exception.
(I think, the problem has nothing to do with properties being virtual or not.)
Edit
You can also put the ForeignKey attribute on the navigation properties and specify what's the name of the FK properties:
...
[ForeignKey("ProfileId")]
public virtual Profiles Profile { get; set; }
...
[ForeignKey("ProfileBlockedId")]
public virtual Profiles ProfileBlocked { get; set; }
...
This leads to the same mapping and it's only a matter of taste what you prefer, as far as I can tell.
I'm facing the same problem, but I can;t sole it using the suggested ForeignKey attribute.
I have installed the MySQL Connector/NET 6.4.3.0. When I run my project I get almost the same error, but referenced to System.Data.Entity. Shouldn;t that be MySql.Data.Entity?
Can you show me how to possibly modify my Web.config or references to work with MySQL.
EDIT
With some help (other post) and trail and error, I got it working too.
Related
I am working on .NET CORE 6 along with EF CORE 7. I need to seed data in joining table but unable to do so and get error.
I am seed FileTypeId but not sure why EF core migration throwing error...
error
The seed entity for entity type 'JobFileType' cannot be added because it has the navigation 'FileType' set. To seed relationships, add the entity seed to 'JobFileType' and specify the foreign key values {'FileTypeId'}. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the involved property values.
ClassA
public class JobProfile
{
public JobProfile()
{
this.JobFileTypes = new HashSet<JobFileType>();
}
public Guid JobProfileId { get; set; }
public string Name { get; set; }
public ICollection<JobFileType>? JobFileTypes { get; set; }
}
ClassB
public class FileType
{
public FileType()
{
this.JobFileTypes = new HashSet<JobFileType>();
}
public Guid FileTypeId { get; set; }
public string Extension { get; set; } = string.Empty;
public ICollection<JobFileType>? JobFileTypes { get; set; }
}
Joing Table
public class JobFileType
{
public Guid JobFileTypeId { get; set; }
public Guid JobProfileId { get; set; }
public JobProfile JobProfile { get; set; } = new JobProfile();
public Guid FileTypeId { get; set; }
public FileType FileType { get; set; } = new FileType();
}
Seed Extension
public static class JobFileTypeSeed
{
public static void Seed(this ModelBuilder modelBuilder)
{
modelBuilder.Entity<JobFileType>()
.HasData(
new JobFileType {JobFileTypeId = Guid.Parse("aaa"), JobProfileId = Guid.Parse("ccc"), FileTypeId = Guid.Parse("yyy") },
new JobFileType { JobFileTypeId = Guid.Parse("bbb"), JobProfileId = Guid.Parse("ccc"), FileTypeId = Guid.Parse("zzz") }
);
}
}
config
internal class JobFileTypeConfiguration : IEntityTypeConfiguration<JobFileType>
{
public void Configure(EntityTypeBuilder<JobFileType> builder)
{
builder.ToTable("JobFileType", "dbo");
builder.HasKey(column => column.JobFileTypeId);
builder
.HasOne(jobFileType => jobFileType.JobProfile)
.WithMany(jobProfile => jobProfile.JobFileTypes)
.HasForeignKey(jobFileType => jobFileType.JobProfileId);
builder
.HasOne(jobFileType => jobFileType.FileType)
.WithMany(fileType => fileType.JobFileTypes)
.HasForeignKey(jobFileType => jobFileType.FileTypeId);
}
}
There is not much to say about the concrete issue (which btw is not specific to joining entity, but any entity model seeding):
I am seed FileTypeId but not sure why EF core migration throwing error...
as the cause of the issue is included at the beginning of the error message:
because it has the navigation 'FileType' set.
And your entity has
public FileType FileType { get; set; } = new FileType();
// ^ ^ ^
// the problem
and the same for
public JobProfile JobProfile { get; set; } = new JobProfile();
which will be the next error if you resolve the original.
Remove both navigation property initializers (= new ...) and the problem will be gone.
As a general rule, you should never initialize reference navigation properties because it causes many side effects and/or improper behaviors (not only for seeding, but also eager/lazy/explicit data loading). Initializing collection navigation properties is arbitrary, but ok. Only reference navigation property initialization must be avoided. For more info, see EF codefirst : Should I initialize navigation properties? - quite old EF topic, but still applies.
If you are trying to resolve NRT warnings (as I guess), initializing with new is definitely not a proper way. One reason I don't like NRT is because it is forcing people to use "workarounds" for preventing compiler warnings, which in fact break the primary functionality. Specifically in EF Core, enabling NRT also changes the optional/required attribute of some properties, hence database column types (most noticeable for string properties/columns and reference navigations). You could read more about this in the Working with Nullable Reference Types topic in the official EF Core documentation, but in general I would just disable NRT for EF entity model classes.
The proper order is to set the "master data" first and then try to set the join table, as you would expect.
The defaulting
{get;set;} = new Something();
Could be the offending declaration, since any instance upon creation will have the relation JobFileType already set
Situation
I have searched for the answer to this extensively (on SO and elsewhere) and I am aware that there are many questions on SO by this same title.
I had a table mapping and model that were working. Then the schema was changed (I do not have direct control of the DB) such that a new Primary Key was introduced and the old Primary Key became the Foreign Key to another table. I believe this is the heart of the problem as no other entities seem to have issues
Mapping
Here is the method that maps my entity (called from OnModelCreating)
private static void MapThing(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Thing>().ToTable("ThingTable");
modelBuilder.Entity<Thing>().HasKey(p => p.Id);
modelBuilder.Entity<Thing>().Property(p => p.Id).HasColumnName("NewId");
modelBuilder.Entity<Thing>().Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<Thing>().Property(p => p.FileName).HasColumnName("ColumnWhosNameChanged");
modelBuilder.Entity<Thing>().HasRequired(p => p.MetaDataOnThing);
}
The old PK of the table is now defined as a property on the model and it is the same name as the column (the reason it is not defined in the mapping above).
Model
Here is the Model (I have applied names that I hope will make it more clear what has changed):
public class Thing
{
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
//This used to be the PK, its names (Property AND Column) have not changed
public int OldId { get; set; }
//The column name for FileName changed to something else
public string FileName { get; set; }
//Unchanged
public byte[] Document { get; set; }
public string ContentType { get; set; }
//Navigation Property
public ThingMetaData MetaDataOnThing { get; set; }
}
Integration test
I removed a lot of structure to, hopefully, make it clear..the test is pretty straight forward
[TestMethod]
public void ThenThingWillBePersisted()
{
var thing = new Thing()
{
OldId = metaDataObject.Id,
Document = new byte[] { 42 },
FileName = "foo.jpg",
ContentType = "image/jpeg"
};
context.Things.Add(thing);
context.SaveChanges();
}
This test produces the error "A dependent property in a ReferentialConstraint is mapped to a store-generated column. Column:'NewId'" and the inner exception points to the NewId as being the issue. It does so on the SaveChanges() call.
Admittedly, I have a lot more experience with nHibernate than I do with Entity Framework but I am pretty sure my mappings and model are setup properly.
Has anyone seen this issue and how did you solve it?
I have just upgraded from EF 4.0.0 to EF 4.3.1.
I am using Visual Studio 2010 Ultimate on Windows XP updated to latest release and all Windows updates/patches applied. The database engine I'm using is SQL Server 2008 R2 Developers Edition.
The following code works perfectly under EF 4.0.0 but not under EF 4.3.1.
public class ItemBase
{
public DateTime Created { get; set; }
public int CreatedByUserID { get; set; }
public DateTime LastModified { get; set; }
public int LastModifiedByUserID { get; set; }
public User CreatedBy { get; set; }
public User LastModifiedBy { get; set; }
public ItemBase()
{
CreatedByUserID = -1;
LastModifiedByUserID = -1;
CreatedBy = null;
LastModifiedBy = null;
}
}
public class User : ItemBase
{
public int UserID { get; set; }
public string LoginName { get; set; }
public string Password { get; set; }
public string EmailAddress { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public string DisplayName { get; set; }
public User() : base()
{
UserID = -1;
LoginName = String.Empty;
Password = String.Empty;
EmailAddress = String.Empty;
Firstname = String.Empty;
Lastname = String.Empty;
DisplayName = String.Empty;
}
}
protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>().Property(u => u.UserID).HasDatabaseGenerationOption(DatabaseGenerationOption.Identity);
}
The only thing that has changed is the version of Entity Framework I'm using.
I have checked the references etc and everything is as expected.
As you can see from the code above, the User class inherits from ItemBase which in turn has a reference to a User instance. The underlying User table contains all the properties from the User class and the ItemBase class (except for the two navigation properties public User CreatedBy { get; set; } and public User LastModifiedBy { get; set; })
Running this code under 4.0.0 everything works as expected, not a single problem or issue whatsoever.
BUT, when I run the same code under 4.3.1 (without any changes whatsoever to anything else, including the database I'm using) I get the following error:
"Unable to determine the principal end of an association between the types 'User' and 'User'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations."
So I then added the following two lines to the OnModelCreating method:
modelBuilder.Entity<User>().HasRequired(u => u.CreatedBy).WithMany().HasForeignKey(k => k.CreatedByUserID);
modelBuilder.Entity<User>().HasRequired(u => u.LastModifiedBy).WithMany().HasForeignKey(k => k.LastModifiedByUserID);
I then get these strange errors:
"The provider did not return a ProviderManifestToken string."
"A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections.
(provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)"
I also noticed loads and loads of these errors in the output window:
"A first chance exception of type 'System.Data.SqlClient.SqlException' occurred in System.Data.dll"
However, these errors appear to be a bit of a red-herring, as the database is fine, available, and the connection string is perfect too. If I subsequently undo the changes to the OnModelCreating method I get the original error again, so I don't believe the error messages I'm getting actually reflect the underlying problem that's occurring here.
So, based on all of this, I come to the following conclusions:
There is a bug in version 4.3.1 of the Entity Framework?
The fact that my code worked under 4.0.0 without the extra two lines
in the OnModelCreating method was probably due to checks not being
made in 4.0.0 which are now subsequently being made in 4.3.1?
I need to add something extra to my configuration/code, or I'm
missing something else to make this work again under 4.3.1?
Can anyone shed some light on this for me? Its driving me nuts!
Many thanks for your time on this.
Kind Regards
Steve
It looks like you have been using a pre-release version of EF 4.1. Probably CTP4 or CTP5. This is apparent because:
ModelBuilder was renamed to DbModelBuilder before 4.1 RTM
DatabaseGenerationOption was renamed to DatabaseGeneratedOption
The exception you are seeing was introduced before EF 4.1 was RTM'ed
Given this, I'm not 100% sure what model was being created with the pre-release version you were using. With 4.1 and above the two navigation properties are detected as inverses of each other and Code First tries to make a 1:1 relationship between User and User. Code First cannot determine the principal for this relationship so rather than guessing it throws asking you to provide it.
However, looking at your model it is clear that this is not what you want anyway. It seems much more likely that you want two 1:* uni-directional navigation props--one for CreatedBy and one for LastModifiedBy. This is what you setup in your OnModelCreating call.
With the changes made to the names of the classes to match 4.1/4.3 and with the code added to OnModelCreating, your code works fine for me on EF 4.3.1.
With regard to not being able to make the connection, you say that the connection string is correct, in which case it must be a case of EF not finding it. Assuming it is in your app.config, then you need to pass the name of it to the DbContext constructor. For example:
public class MyContext : DbContext
{
public MyContext()
: base("name=MyConnectionStringName")
{
}
}
If you're using the connection string in some other way then we'll need more details on that.
I have a table in my database called SEntries (see below the CREATE TABLE statement). It has a primary key, a couple of foreign keys and nothing special about it. I have many tables in my database similar to that one, but for some reason, this table ended up with a "Discriminator" column on the EF Proxy Class.
This is how the class is declared in C#:
public class SEntry
{
public long SEntryId { get; set; }
public long OriginatorId { get; set; }
public DateTime DatePosted { get; set; }
public string Message { get; set; }
public byte DataEntrySource { get; set; }
public string SourceLink { get; set; }
public int SourceAppId { get; set; }
public int? LocationId { get; set; }
public long? ActivityId { get; set; }
public short OriginatorObjectTypeId { get; set; }
}
public class EMData : DbContext
{
public DbSet<SEntry> SEntries { get; set; }
...
}
When I try to add a new row to that table, I get the error:
System.Data.SqlClient.SqlException: Invalid column name 'Discriminator'.
This problem only occurs if you are inheriting your C# class from another class, but SEntry is not inheriting from anything (as you can see above).
In addition to that, once I get the tool-tip on the debugger when I mouse over the EMData instance for the SEntries property, it displays:
base {System.Data.Entity.Infrastructure.DbQuery<EM.SEntry>} = {SELECT
[Extent1].[Discriminator] AS [Discriminator],
[Extent1].[SEntryId] AS [SEntryId],
[Extent1].[OriginatorId] AS [OriginatorId],
[Extent1].[DatePosted] AS [DatePosted],
[Extent1].[Message] AS [Message],
[Extent1].[DataEntrySource] AS [DataE...
Any suggestions or ideas where to get to the bottom of this issue? I tried renaming the table, the primary key and a few other things, but nothing works.
SQL-Table:
CREATE TABLE [dbo].[SEntries](
[SEntryId] [bigint] IDENTITY(1125899906842624,1) NOT NULL,
[OriginatorId] [bigint] NOT NULL,
[DatePosted] [datetime] NOT NULL,
[Message] [nvarchar](500) NOT NULL,
[DataEntrySource] [tinyint] NOT NULL,
[SourceLink] [nvarchar](100) NULL,
[SourceAppId] [int] NOT NULL,
[LocationId] [int] NULL,
[ActivityId] [bigint] NULL,
[OriginatorObjectTypeId] [smallint] NOT NULL,
CONSTRAINT [PK_SEntries] PRIMARY KEY CLUSTERED
(
[SEntryId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[SEntries] WITH CHECK ADD CONSTRAINT [FK_SEntries_ObjectTypes] FOREIGN KEY([OriginatorObjectTypeId])
REFERENCES [dbo].[ObjectTypes] ([ObjectTypeId])
GO
ALTER TABLE [dbo].[SEntries] CHECK CONSTRAINT [FK_SEntries_ObjectTypes]
GO
ALTER TABLE [dbo].[SEntries] WITH CHECK ADD CONSTRAINT [FK_SEntries_SourceApps] FOREIGN KEY([SourceAppId])
REFERENCES [dbo].[SourceApps] ([SourceAppId])
GO
ALTER TABLE [dbo].[SEntries] CHECK CONSTRAINT [FK_SEntries_SourceApps]
GO
Turns out that Entity Framework will assume that any class that inherits from a POCO class that is mapped to a table on the database requires a Discriminator column, even if the derived class will not be saved to the DB.
The solution is quite simple and you just need to add [NotMapped] as an attribute of the derived class.
Example:
class Person
{
public string Name { get; set; }
}
[NotMapped]
class PersonViewModel : Person
{
public bool UpdateProfile { get; set; }
}
Now, even if you map the Person class to the Person table on the database, a "Discriminator" column will not be created because the derived class has [NotMapped].
As an additional tip, you can use [NotMapped] to properties you don't want to map to a field on the DB.
Here is the Fluent API syntax.
http://blogs.msdn.com/b/adonet/archive/2010/12/06/ef-feature-ctp5-fluent-api-samples.aspx
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName {
get {
return this.FirstName + " " + this.LastName;
}
}
}
class PersonViewModel : Person
{
public bool UpdateProfile { get; set; }
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// ignore a type that is not mapped to a database table
modelBuilder.Ignore<PersonViewModel>();
// ignore a property that is not mapped to a database column
modelBuilder.Entity<Person>()
.Ignore(p => p.FullName);
}
I just encountered this and my problem was caused by having two entities both with the System.ComponentModel.DataAnnotations.Schema.TableAttribute referring to the same table.
for example:
[Table("foo")]
public class foo
{
// some stuff here
}
[Table("foo")]
public class fooExtended
{
// more stuff here
}
changing the second one from foo to foo_extended fixed this for me and I'm now using Table Per Type (TPT)
I had a similar problem, not exactly the same conditions and then i saw this post. Hope it helps someone. Apparently i was using one of my EF entity models a base class for a type that was not specified as a db set in my dbcontext. To fix this issue i had to create a base class that had all the properties common to the two types and inherit from the new base class among the two types.
Example:
//Bad Flow
//class defined in dbcontext as a dbset
public class Customer{
public int Id {get; set;}
public string Name {get; set;}
}
//class not defined in dbcontext as a dbset
public class DuplicateCustomer:Customer{
public object DuplicateId {get; set;}
}
//Good/Correct flow*
//Common base class
public class CustomerBase{
public int Id {get; set;}
public string Name {get; set;}
}
//entity model referenced in dbcontext as a dbset
public class Customer: CustomerBase{
}
//entity model not referenced in dbcontext as a dbset
public class DuplicateCustomer:CustomerBase{
public object DuplicateId {get; set;}
}
Another scenario where this occurs is when you have a base class and one or more subclasses, where at least one of the subclasses introduce extra properties:
class Folder {
[key]
public string Id { get; set; }
public string Name { get; set; }
}
// Adds no props, but comes from a different view in the db to Folder:
class SomeKindOfFolder: Folder {
}
// Adds some props, but comes from a different view in the db to Folder:
class AnotherKindOfFolder: Folder {
public string FolderAttributes { get; set; }
}
If these are mapped in the DbContext like below, the "'Invalid column name 'Discriminator'" error occurs when any type based on Folder base type is accessed:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Folder>().ToTable("All_Folders");
modelBuilder.Entity<SomeKindOfFolder>().ToTable("Some_Kind_Of_Folders");
modelBuilder.Entity<AnotherKindOfFolder>().ToTable("Another_Kind_Of_Folders");
}
I found that to fix the issue, we extract the props of Folder to a base class (which is not mapped in OnModelCreating()) like so - OnModelCreating should be unchanged:
class FolderBase {
[key]
public string Id { get; set; }
public string Name { get; set; }
}
class Folder: FolderBase {
}
class SomeKindOfFolder: FolderBase {
}
class AnotherKindOfFolder: FolderBase {
public string FolderAttributes { get; set; }
}
This eliminates the issue, but I don't know why!
I get the error in another situation, and here are the problem and the solution:
I have 2 classes derived from a same base class named LevledItem:
public partial class Team : LeveledItem
{
//Everything is ok here!
}
public partial class Story : LeveledItem
{
//Everything is ok here!
}
But in their DbContext, I copied some code but forget to change one of the class name:
public class MFCTeamDbContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Other codes here
modelBuilder.Entity<LeveledItem>()
.Map<Team>(m => m.Requires("Type").HasValue(ItemType.Team));
}
public class ProductBacklogDbContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Other codes here
modelBuilder.Entity<LeveledItem>()
.Map<Team>(m => m.Requires("Type").HasValue(ItemType.Story));
}
Yes, the second Map< Team> should be Map< Story>.
And it cost me half a day to figure it out!
Old Q, but for posterity...it also also happens (.NET Core 2.1) if you have a self-referencing navigation property ("Parent" or "Children" of the same type) but the Id property name isn't what EF expects. That is, I had an "Id" property on my class called WorkflowBase, and it had an array of related child steps, which were also of type WorkflowBase, and it kept trying to associate them with a non-existent "WorkflowBaseId" (the name i suppose it prefers as a natural/conventional default). I had to explicitly configure it using HasMany(), WithOne(), and HasConstraintName() to tell it how to traverse. But I spent a few hours thinking the problem was in 'locally' mapping the object's primary key, which i attempted to fix a bunch of different ways but which was probably always working.
this error happen with me because I did the following
I changed Column name of table in database
(I did not used Update Model from database in Edmx) I Renamed manually Property name to match the change in database schema
I did some refactoring to change name of the property in the class to be the same as database schema and models in Edmx
Although all of this, I got this error
so what to do
I Deleted the model from Edmx
Right Click and Update Model from database
this will regenerate the model, and entity framework will not give you this error
hope this help you
I'm faced with a confusing problem where in my Edit or Create action result methods, EF4 will throw a DbEntityValidationException with the inner message stating:
The field Body must be a string or
array type with a maximum length of
'128'.
The model in question looks like this:
[Table("tblArticles")]
public class Article
{
[Key]
public int ID { get; set; }
[Required(ErrorMessage="Title must be included")]
public string Title { get; set; }
[AllowHtml]
public string Body { get; set; }
[Required(ErrorMessage="Start Date must be specified")]
[Display(Name="Start Date")]
[DisplayFormat(DataFormatString="dd-mm-yyyy")]
public DateTime? StartDate { get; set; }
[Required(ErrorMessage = "End Date must be specified")]
[Display(Name = "End Date")]
public DateTime? EndDate { get; set; }
public int Priority { get; set; }
public bool Archived { get; set; }
public virtual ICollection<ArticleImage> Images { get; set; }
}
The "Body" field in the actual database is of type Text, so there's no obvious limit there. The data that I'm trying to post is this:
<p>
This is an example to confirm that new articles are looking right.</p>
<p>
<img alt="" src="http://www.google.co.nz/logos/2011/houdini11-sr.jpg"
style="width: 160px; height: 56px; float: left;" /></p>
An example of the Edit method looks like this:
[HttpPost]
public ActionResult Edit(Article article)
{
if (ModelState.IsValid)
{
try
{
articleRepository.Update(article);
}
catch (DbEntityValidationException dbevEx)
{
ErrorSignal.FromCurrentContext().Raise(dbevEx);
ModelState.AddModelError("FORM", dbevEx);
return View("Edit", article);
}
// Other exception handling happens...
}
return RedirectToAction("Index");
}
And finally, the method that actually does the grunt work is:
public void Update(T Entity)
{
dbset.Attach(Entity);
db.Entry(Entity).State = System.Data.EntityState.Modified;
db.Commit();
}
I can't see anything in code or in the database that might be causing the problem, so where else should I look?
Default length of string field in code first is 128. If you are using EF validation it will throw exception. You can extend the size by using:
[StringLength(Int32.MaxValue)]
public string Body { get; set; }
This post became somehow popular so I'm adding second approach which also works:
[MaxLength]
public string Body { get; set; }
StringLengthAttribute is from System.ComponentModel.DataAnnotations assembly and MaxLengthAttribute is from EntityFramework assembly (EF 4.1).
If you get this error using a Model First approach, check the EF Model: it may be simply that a property on the Entity you're updating has the Max Length attribute set.
For Entity Framework 4.3.1, 5.0.0 and 6.2.0, you can use IsMaxLength().
Property(m => m.Body ).IsRequired().IsMaxLength();
Configures the column to allow the maximum length supported by the database provider.
https://learn.microsoft.com/en-us/dotnet/api/system.data.entity.modelconfiguration.configuration.stringcolumnconfiguration.ismaxlength?view=entity-framework-6.2.0
May be you have used
Property(m => m.Body ).IsRequired().HasMaxLength(128);
On your dbcontext class in OnModelCreating.
So change as per your length
For me, [MaxLength] didn't work. I have added below statement to the context.
modelBuilder.Entity<YourModel>().Property(e => e.YourColumn).HasMaxLength(4000);
I have not tried exceeding "4000" limit but I think it can be extended further. You don't have to keep it 128 as the error showed by compiler.