Can't query value from newly created column - c#

I just added a new column to the database for a project. I confirmed that the column exists the database. I've added the property to my model and my dbset is defined using that model. However, as soon as I try to query that column value, it gives me NotSupportedException.
The specified type member 'screen_icon' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.
Context class
public partial class dml_entities : DbContext
{
public dml_entities() : base("name=dml_entities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
// ...
public virtual DbSet<screen> screen { get; set; }
// ...
}
Model
public partial class screen
{
// ...
public string screen_icon { get; set; }
// ...
}
Controller code
public class ScreenController : ApiController
{
private dml_entities db = new dml_entities()
public IQueryable<object> Get_screen()
{
return db.screen.Select(e => new { icon = e.screen_icon });
}
}
Edit:
When I db.screen.ToList() before selecting from it, the error goes away, but 'screen_icon' is always null, even if there actually is a value in the db.
For whatever reason, it seems like my code doesn't believe that the column exists in the database.
Edit2:
Not sure if its relevant, but the exception does not seem to trigger in the controller code itself. Attempting to try{} catch{} creates the same result.

Does screen_icon has getter and setter or it is a variable? Should be a property
What is the name and type in database? Maybe try forcing column name with attrbiute like:
[Column("screen_icon")]
public string screen_icon { get; set; }

It turns out that the project was using an edmx file to manage their models. Due to the amount of noise in the file I edited and the fact that I found it through "go to definition" and the not the file explorer, I didn't realize that the model file was generated from the Entities.edmx file.
Once I updated the model in from the edmx designer, my code worked as expected. And I learned that its important to keep an eye out for comments that inform you not to edit it manually because its an auto-generated file.

Try:
return db.screen.ToList().Select(e => new { icon = e.screen_icon });

Related

Entity Framework Core get data from stored procedure and then convert into view model without DbSet

I have a function in the repository, GetForms, the purpose of the function is to call a stored procedure and return rows with data. Everything is working fine until now.
Function
public IEnumerable<FormBO> GetForms()
{
var id = "1"
var Query= _context.FormBO.FromSqlRaw("dbo.SP_Core #pin_ID={0}", id)
.AsNoTracking().ToList(); //3K line of sp
return Query;
}
Model
public class FormBO
{
[Key]
public int? ID { get; set; }
public int? secondid { get; set; }
......
}
DbContext
Added this code, so context thinks it is a table in the database and, I don't have to do more stuff
public virtual DbSet<FormBO> FormBO { get; set; }
The problem
Whenever we scaffold the database and the db context, it regenerates all the files and code, so it removes the
public virtual DbSet<FormBO> FormBO { get; set; }
And we have to add this line manually is there any way I can change the logic, so I don't have to add this code (DBset<FormBO>) to DbContext every time a dba updates the database...
What I found
I found that if I change the model to ".Database" and FromSqlRaw to ExecuteSqlRaw, but it is just returning the count as int not a list of rows.
public IEnumerable<FormBO> GetForms()
{
var id = "1"
var Query = _context.Database.ExecuteSqlRaw("dbo.SP_Core #pin_ID={0}", id)
.AsNoTracking().ToList(); //3K line of sp
return Query;
}
If it is possible it automatically add the DBSet to context whenever we update the code which I don't think we will able to do.
or
Get the query result without the dbset model and then I will use foreach loop to add it in FormBO model it is just 10 rows
Since the table doesn't actually exist in the database, the built in scaffolding process won't attempt to create it.
However you could probably replace the IScaffoldingModelFactory service, with an implementation that extends RelationalScaffoldingModelFactory, and use the code-first fluent api to define meta data for tables that don't really exist.
You could probably use this type of approach to define types for all table values in the database. Since EF Core 5 is adding support for table values, maybe they'll do it for you, but I haven't tested that.
public class MyModelFactory : RelationalScaffoldingModelFactory
{
public MyModelFactory(
IOperationReporter reporter,
ICandidateNamingService candidateNamingService,
IPluralizer pluralizer,
ICSharpUtilities cSharpUtilities,
IScaffoldingTypeMapper scaffoldingTypeMapper,
LoggingDefinitions loggingDefinitions)
: base(reporter, candidateNamingService, pluralizer, cSharpUtilities, scaffoldingTypeMapper, loggingDefinitions)
{
}
protected override ModelBuilder VisitDatabaseModel(ModelBuilder modelBuilder, DatabaseModel databaseModel)
{
modelBuilder.Entity<FormBO>(entity =>
{
// ...
});
return base.VisitDatabaseModel(modelBuilder, databaseModel);
}
}
services.AddDbContextPool<ContextType>(o =>
{
o.ReplaceService<IScaffoldingModelFactory, MyModelFactory>();
// ...
});
Of course there's an easy answer too. The scaffolded context is a partial class. Just define your other DbSet in another source file.

How to manually set entity primary key in Entity Framework code first database?

Well, I have the following model structure: I have one class - DatabaseEntity which is basically
public class DatabaseEntity
{
public int Id { get; set; }
}
so each entity like product, category etc will inherit DatabaseEntity and have Id property. Also I have typical EntityFramework repository class with InsertOrUpdate method:
private readonly DbContext _database;
public void InsertOrUpdate<TObject>(TObject entity) where TObject : DatabaseEntity
{
if(entity.Id == default(int))
{
// New entity
DbSet<TObject>().Add(entity);
}
else
{
// Existing entity
_database.Entry(entity).State = EntityState.Modified;
}
_database.SaveChanges();
}
Then I download from eBay via eBay api list of categoies I have to add to database. Basically category is:
public class EbayCategory : DatabaseEntity
{
// It has Id since it inherits DatabaseEntity
public string Name { get; set; }
// ... some other properties
}
But, the problem is, when I download those categories I download and their Id properties, which, of course, already have values. And when I try to save them to database like:
public void UpdateCategories(IEnumerable<EbayCategory> newCategories)
{
foreach (var newCategory in newCategories)
{
_repository.InsertOrUpdate(newCategory);
}
}
I face some issues... First of all, entity.Id != default(int) because it has value, so repository tries to update this entity, instead of adding, but it is not in the database or context so it throws the following exception:
System.Data.Entity.Infrastructure.DbUpdateConcurencyException
"Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries."
... because it thinks that someone else deleted entity which I am trying to update. How can I save this InsertOrUpdate logic, since a lot of projects are based on it, and be able to add items (EbayCategories) with primary key (Id) to database and then update/delete them like other entities without discarding EbayCategory.Id value?
To allow you to manually generate Ids you need a class that has a manually generated ID - so it cannot inherit from DatabaseEntity
public class EbayCategory
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
public string Name { get; set; }
// ... some other properties
}
Now you will need a different InsertOrUpdate to handle entities that have manually generated keys:
public void InsertOrUpdate(EbayCategory entity)
{
if(Find(entity.ID == null)
{
// New entity
DbSet<EbayCategory>().Add(entity);
}
else
{
// Existing entity
_database.Entry(entity).State = EntityState.Modified;
}
_database.SaveChanges();
}
Colin's answer above quite correctly shows how to achieve this setting using data annotations.
But in the presented problem the entity is a subclass so you can't add the annotation without changing the entity class.
There is an alternative configuration method: Fluent Configuration. Here's my example using an EntityTypeConfiguration class:
public class LookupSchoolsConfiguration : EntityTypeConfiguration<LookupSchools>
{
public LookupSchoolsConfiguration()
{
Property(l => l.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
}
}
You can also add configuration directly to the modelBuilder as per this post: https://stackoverflow.com/a/4999894/486028

DataSet ToList method returns empty List, even though it has elements

Sorry if somebody has already asked this question. I've been looking around but couldn't find anything related.
So, I am using Entity Framework and I am trying to load the list of "Idiomas" from the dataset using the ToList method through the following code:
//List<Idioma> ans = new List<Idioma>(contexto.Idiomas);
return contexto.Idiomas.ToList();
However, the method is returning an empty list, even though I can see through the debugger that the DataSet has elements.
EDIT
I have not put any extra code because there is not any extra code besides those two lines.
I just create a Entity Framework model-first, generated the database, and updated the model from the database to make sure everything was ok.
Contexto is a instance from the class LivroContexto, which implements DbContext (auto generated by vs2012, see below).
LivroContainer:
public partial class LivroContainer : DbContext
{
public LivroContainer() : base("name=LivroContainer")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
}
public DbSet<Idioma> Idiomas { get; set; }
}
Idiomas:
public partial class Idioma
{
public Idioma()
{
this.Traducaos = new HashSet<Traducao>();
}
public int IdIdioma { get; set; }
public string Lingua { get; set; }
public virtual ICollection<Traducao> Traducaos { get; set; }
}
Thank you
nobody can see, why your code is not working, from the amount of code you have posted.
however, make sure following :
the class of the instance contexto inherits DbContext or any child class inheriting DbContext.
make sure, in case, you have not generated the database, through the code,rather mapped an existing database, to a codefirst frontend, that DbSet<Idioma> Idiomas is mapped to proper table. ie.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Idioma>().ToTable("IdiomaTableNameInDatabase");
}
make sure, your connectionString name, that you passed in the DbContext base constructor is present in the web.config, and if you have not passed anything, make sure a connectionString with the name of your DbContext inheriting class is there.
If all these are correct, there is absolutely no reason, why contexto.Idiomas.ToList() won't return anything.
and also, say, your context class is MyContext, then it should be like this:
public class MyContext:DbContext
{
public MyContext:base("ConnectionStringName")
{
}
//--dbSet properties
public DbSet<Idioma> Idiomas{get;set;}
//other overridden methods
}
which you use, on your upper layers like this:
public List<Idioma> GetAllIdiomas()
{
MyContext contexto = new MyContext();
return contexto.Idiomas.ToList();
}

ModelValidationException: Name 'AnonymousUID' cannot be used in type 'CodeFirstDatabaseSchema.AnonymousUID'

I am using Entity Framework to model an existing database. One of the database tables contains a column with the same name as the table, AnonymousUID.
I use the Entity Framework Power Tools function Reverse Engineer Code First to generate the model classes and mappings. The reverse engineering procedure automatically renames the AnonymousUID class member (to AnonymousUID1) to avoid that a member name is the same as the class name. The generated model class thus looks like this:
public partial class AnonymousUID
{
public string UID { get; set; }
public string AnonymousUID1 { get; set; }
}
and the EF mapping constructor is implemented like this:
public AnonymousUIDMap()
{
// Primary Key
this.HasKey(t => t.UID);
// Properties
this.Property(t => t.UID).IsRequired().HasMaxLength(64);
this.Property(t => t.AnonymousUID1).IsRequired().HasMaxLength(64);
// Table & Column Mappings
this.ToTable("AnonymousUID");
this.Property(t => t.UID).HasColumnName("UID");
this.Property(t => t.AnonymousUID1).HasColumnName("AnonymousUID");
}
The database context class is implemented like this:
public partial class MyDbContext : DbContext
{
// Constructors...
public DbSet<AnonymousUID> AnonymousUIDs { get; set; }
...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new AnonymousUIDMap());
...
}
}
This is all good and well, and the code builds without problems. But when I try to access arbitrary contents of the database:
using (var context = new MyDbContext())
{
var foos = from foo in context.Foos select foo;
...
}
the following exception is nonetheless thrown:
System.Data.Entity.ModelConfiguration.ModelValidationException :
One or more validation errors were detected during model generation:
\tAnonymousUID: Name: Name 'AnonymousUID' cannot be used in type
CodeFirstDatabaseSchema.AnonymousUID'. Member names cannot be the
same as their enclosing type.
There is obviously some additional mapping build-up going on in CodeFirstDatabaseSchema, and this procedure is not able to avoid the class/member name clash.
Why does this error occur? After all, the reverse engineering procedure managed to circumvent the naming issue.
Without modifying the schema of the already established database, is there some way I can avoid this exception from being thrown?
I am using Entity Framework 6.0 (pre-release) from Nuget in a .NET Framework 4 project.
As I guessed at in the comment above, change the column name to start with a lowercase 'a'
...HasColumnName("anonymousUID");
Let's hope this is a pre release defect and is fixed in the RTM ;-)
Is the code you displayed the only place you're using the AnonymousUID name? What is the name of your DbSet in the generated DbContext?
I built a test app, and didn't get any errors, here it in it's entirety:
public partial class AnonymousUID
{
[Key]
public int UID { get; set; }
public string AnonymousUID1 { get; set; }
}
public class Model : DbContext
{
public DbSet<AnonymousUID> AnonymousUIDs { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<AnonymousUID>()
.Property(a => a.AnonymousUID1)
.HasColumnName("AnonymousUID");
modelBuilder.Entity<AnonymousUID>()
.ToTable("AnonymousUID");
}
}
class Program
{
static void Main(string[] args)
{
var model = new Model();
var a = new AnonymousUID();
a.AnonymousUID1 = "hello world";
model.AnonymousUIDs.Add(a);
model.SaveChanges();
var applications = model.AnonymousUIDs.ToList();
Console.WriteLine(applications.Count);
Console.ReadLine();
}
}
Created this database:
It was able to create, insert, and then display the count of the table.
I had a similar issue, but I could not rename the column because it would break legacy code. The type names that Power Tools generated are all lowercase. I changed the capitalization on the conflicting types, and it worked.
I suspect that CodeFirstDatabaseSchema is maintaining lowercase property names, but I am not sure. All I know is that changing my lowercase type names to properly capitalized type names fixed it. I hope that is helpful for someone.

The property is not a declared property on type 'class'

I got the error The property 'Rank' is not a declared property on type 'MasterUser'. Verify that the property has not been explicitly excluded from the model by using the Ignore method or NotMappedAttribute data annotation. Make sure that it is a valid primitive property. I checked my model class and it is there.
public class MasterUser
{
//many other properties...
public virtual char Rank { get; set; }
//more properties below
}
I also checked my db context and it is also there and mapped perfectly.
public class BBDataContext : DbContext
{
public DbSet<MasterUser> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
#region MUSR_USRID mapping
//Mapped properties above....
modelBuilder.Entity<MasterUser>()
.Property(usr => usr.Rank).HasColumnName("MUSR_RANK");
//More mapped properties..
modelBuilder.Entity<MasterUser>().ToTable("dbo.MUSR_FIL");
#endregion
base.OnModelCreating(modelBuilder);
}
}
In the table, MUSR_RANK is nullable with a char datatype.
How can I fix this? Does the database have an effect on this? I am currently using SQL Server 2000.
Thanks for the help.
Primitive Data Types Supported in the Entity Data Model
So you have to use a string instead of a char, I think
and add some datas in OnModelCreating
modelBuilder.Entity<MasterUser>()
.Property(usr => usr.Rank).HasColumnName("MUSR_RANK")
.HasMaxLength(1)
.IsFixedLength()
.IsUnicode(false);
I got the same error and was searching for help when I found this page. I know this post is old, but since my solution is different, I am posting in case it helps someone else. I am using EF 6.
My error was caused because I inadvertently made a property of my model class readonly.
[Key]
[StringLength(10)]
public string ProjectNumber { get; }
The EF error wasn't very descriptive of the problem. As soon as I added the set accessor, the error disappeared.

Categories