Entity Framework Core exception renaming column - c#

I have a .Net6 WinForms application using Entity Framework Core 6.0.3 and I am trying to read a simple table from a SQL Server database. I need to rename the column so that it is different in the model than what it is called in the database.
Normally (in EF6, I would add a [Column()] attribute on the property with the new name. However, when I do that it throws an exception reading the data 'Invalid column name' for whatever the new name is.
I have also tried using the modelBuilder and calling the HasColumnName() but get the same error. If I remove the attribute/model builder reference, then no exception occurs, except that I am stuck with the old column name.
[Table("RefTable1")
public partial class SpecialReferenceTable
{
public Int32 Id { get; set;}
[MaxLength(300)]
[Column("NewRefColumn"] // Throws exception Column does not exist: NewRefColumn
public String? OldRefColumn {get;set;}
}
Is there something I am missing with renaming column in Core?

[Column("Column name")] is used for the name of the column in the database table and the name of the property you have is the one you want to change.

Related

EF Core using HasConversion causing DbUpdateConcurrencyException

I am using EF core to store a local copy of a database. When a row is removed from the server database I need to remove that row from the local database using EF Core. I have run into an issue on an entity that uses HasConversion to convert a string property to upper. When EF core tries to delete one of these entities a DbUpdateConcurrencyException is thrown. I think I understand what is causing the issue but I dont know how to resolve it.
The entity in question is defined like this:
public class PartBin : BaseEpiView
{
public string PartNum { get; set; }
public string WarehouseCode { get; set; }
public string BinNum { get; set; }
public decimal OnhandQty { get; set; }
}
Now in the original database on the server the BinNum has values like "Elec101", "Elec102", "ELEC103", "elec104". Note the inconsistent capitalisation. To address this I have made use of HasConversion to convert the values to Upper.
modelBuilder.Entity<PartBin>().Property(p=> p.BinNum)
.HasConversion(v => v.ToUpper(), v => v.ToUpper());
This works and all the BinNum values are in Upper and displayed nicely to the user.
However the problem comes when one of these entries needs to be deleted. EF Core is throwing this error when SaveChanges() is called.
Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: 'Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.'
I think this is caused by the HasConversion because in the database the BinNum is "Elec101" while on the entity it is "ELEC101" so EF Core thinks the data has changed and throws the exception. I need to tell EF core the data has not changed and it is ok to go ahead and delete the row...
What I have tried.
Reading all the docs and SO questions I can find
Remove the HasConversion which did resolve the delete issue but then all the BinNum values have inconsistent capitalistion in the local database.
Use the IsConcurrencyToken() to tell EF Core to look at the PartNum property when considering if an entity has changed. This didnt work.
modelBuilder.Entity<PartBin>().Property(p => p.PartNum).IsConcurrencyToken(true);
On the BaseEpiView class that PartBin inherits from there is a SysRevID. This is the SQL RowVersion and is incremented by the MS SQL server. If this value has not changed then the row has not changed.
public abstract class BaseEpiView : BaseObject, IEpiObject
{
public Byte[] SysRevID { get; set; }
public string Company { get; set; }
}
I tried setting that as the RowVersion in the model Builder.
modelBuilder.Entity<EpicorPartBin>().Property(p => p.SysRevID).IsRowVersion();
but still the DbUpdateConcurrencyException is thrown.
It would seem like using the IsRowVersion() is the correct way to address this issue but it is not working for some reason? Have I implemented it incorrectly?
Other Information:
EF Core 5.0.0-rc.2.20475.6 (I should update to a released version and check that....)
local database is SQLite
Server database is MS SQL Server
EF Core is hosted in a WPF .Net Core app

make column nullable EF 6 Code first in production

I have a web api application using sql server EF 6 code first approach and it's up and running.
Now for a table I want to make a column NULL.
From sql server database side I alter my table definition and able to make the column NULL.
But the class definition has [Required] attribute, which is the reason database save (with null value) still failing even I made database column NULL.
[Required]
[StringLength(512)]
public string Name { get; set; }
I there any solution here?
I understand I need to remove [Required] attribute and this requires a code change. I am looking if some way without code change. this is production .
Removing Required attribute
[StringLength(512)]
public string Name {get;set;}

Could not use property name as that of class for dbset entity framework

I have a table number as below in mysql server, for heads up I am using MVC4 with EF and MYSql as database-
I used database first approach to add entities to my project and since my table contains the number as property which is also the name of table so EF modal generator added that property as number1 as shown below-
When I try to pull data from database using EF query it throws the error saying-
Unknown column 'Extent3.number1' in 'field list'
Basically I want to know how can we use same field name inside class as that of class name for modal class generated.
I don't know about MySQL but this will fix your model in SQL Server:
[Column("number")]
public string number1 { get; set; }
If not you should override the OnModelCreating in your db context.
Test this and tell me to post the other way if this doesn't work.

Entity Framework singularize/pluralize not working as expected

Using EF 6, when we generate the models (dbmx) from our database, we have the checkbox checked that states:
Pluralize or singularize generated object names
However, when the classes are generated, the name of each class is the exact name of the table, and its properties (whether a db type or db set) are the exact name of their respective table as well.
Basically, everything is pluralizing...
public virtual DbSet<Documents> Documents { get; set; } // Shoud be of type 'Document'
public virtual Images Images { get; set; } // should be of type 'Image', and named 'Image' as well
What am I missing here? Seems like EF just isn't naming things correctly.
Edit
I've tested this with singular and plural table names. As mentioned above, the generated code mimics exactly what the table names are. If the table name is Documents, then the type generated in C# is Documents... The type should be Document though.
In another solution, the generated code takes the plural table name Documents, and generates a type called Document out of it. THIS is the expected behavior for our new solution... but it's not working that way for some reason.

Entity Framework Invalid Column

I've looked at lots of other questions on SO but can't get the answer. I have a column in a table called: Sex - Male
I would like to get my hands on whoever named it as it's giving me problems with EF. If I use this:
[Column("Sex - Male")]
public bool Sex { get;set; }
This gives me the error of being incompatible with the model as the field "Sex" could not be found. So I changed to this:
[Column("[Sex - Male]")]
public bool Sex { get;set; }
I then get the message Invalid Column Name [Sex - Male]. Does EF rename columns with spaces in some way as the field does exist and is not any kind of FK?
EDIT
I have found that doing this in the modelBuilder:
modelBuilder.Entity<Student>().Property(x => x.Sex).HasColumnName("Sex - Male");
Causes the same error to appear saying it's incompatible as there is no column called Sex with the same name! I've noticed it occurs on anything I use the Column data annotation for not just this field!
EDIT 2
I created a new application and used a Model Designer to see how it interpreted the column and showed it in the designer as "Sex___Male", however, changing the class to this even with []'s around it still gives me could not find column Sex___Male??
EDIT 3
It appears the error isn't quite what I thought, I found the mapping config works fine when I just use db.Students; and the column is there as expected.
It turns out the area going wrong is this line:
var students = (db as IObjectContextAdapter).ObjectContext.ExecuteStoreQuery<Student>(sql);
So it's clearly the ExecuteStoreQuery that I'm guessing won't use the same mapping configuration therefore sees the column as missing. Not sure why putting the Column annotation on the property in the class doesn't work though??
I have recreated your situation in a test configuration. I was able to succesfully insert and query data using the following configuration
SQL Server 2012
Visual Studio 2013
Entity Framework 6.0.1
If you are using an older version of Entity Framework I would consider updating; that's most likely the cause, however I'm not able to reproduce your environment so this answer is only a guess. I used this code:
Created a table:
create table MyTable2 (
[pk] int not null identity primary key,
[Sex - Male] bit not null);
Class:
public class MyTable2
{
public int pk { get; set; }
public bool Sex { get; set; }
}
Mapping configuration:
this.HasKey(t => t.pk);
this.Property(t => t.Sex).HasColumnName("Sex - Male");
It appears that Entity Framework itself had no issue mapping this column regarding it's normal use however the issue I had is where I was using the ExecuteStoreQuery method to map the model.
It turns out using this means anything you map it to has to have the same names regardless of any data annotations you add on for column (they appear to just get ignored). What I did instead was make a small class with just the fields I needed and changed the sql of the query to Select StudentID As ID, [Sex - Male] As Sex, ...other fields FROM ...etc i.e.
public class StudentReadOnly
{
public int ID { get; set; }
public bool Sex { get;set; }
... other properties
}
And then changed line to:
var students = (db as IObjectContextAdapter).ObjectContext.ExecuteStoreQuery<StudentReadOnly>(sql);
And had no problems. I also found that any properties you put in the class MUST exist in the sql query unlike a usual ef query.

Categories