Method not found HasDatabaseGeneratedOption - c#

I have read all post related to this and i've tried them all but not results.
Im using fluent api to map my models to the database. But when im query i get this Error:
Method not found:
'System.Data.Entity.ModelConfiguration.Configuration.DecimalPropertyConfiguration
System.Data.Entity.ModelConfiguration.Configuration.DecimalPropertyConfiguration.HasDatabaseGeneratedOption(System.Nullable`1<System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption>)'.
My model look like this:
ToTable("table_name");
HasKey(x => x.CounterId)//this property IS NOT NULLABLE
.Property(x => x.CounterId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
.HasColumnName("dbCounter_Id")
.HasPrecision(10, 0)
.IsRequired();
Property(x => x.HouseId)
.HasColumnName("dbHouseId");
Property(x => x.ApplicationId)
.HasColumnName("dbApplication_id");
For some reason .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity) is giving me this error so when i quit it:
HasKey(x => x.CounterId)
.Property(x => x.PageId)
.HasColumnName("dbCounter_Id")
.HasPrecision(10, 0)
.IsRequired();
I get not error but as im lucky as hell, when im trying to add a record to that table i get insert identity exception. I cant neither added nor quit it the HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity) method.
Important: The key CounterId is not type INTEGER, is DECIMAL(10,0) instead. Could that be the problem here? I cannot change the datatype of the column since there are a lot of app in production that will be affect in the worst way.
Hope i can get any help.

You should make it in this way
ToTable("table_name");
HasKey(x => x.CounterId); // you should split HasKey from Property
Property(x => x.CounterId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
.HasColumnName("dbCounter_Id")
.HasPrecision(10, 0)
.IsRequired();
Property(x => x.HouseId)
.HasColumnName("dbHouseId");
Property(x => x.ApplicationId)
.HasColumnName("dbApplication_id");

You should try to remove the nuget package from all projects. Then add it again.
I don't know why but it just worked for me, even if the package was the same.

One of the reasons for this error is because of different .NET versions of your projects. For e.g. if your EF DbContext class is created in a project of .NET v4.5, and if the Web Application you are using it in is of .NET v4.0, then you might get this error at run-time.
Ideally, it should error at compile time. But, some times Visual Studio compiles fine, especially for older "Website" type projects. And, when the application actually runs, that is when the error occurs.
So, to fix this, make sure that .NET framework version of your client application (that uses the EF DbContext class) is >= .NET version of project containing the DbContext.

I had a similar issue with EF6 and ASP.Net 3.1. This answer helped nudge me in the right direction, but I solved it slightly differently. All I needed to do was add the following in my model class that the table was based on:
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Round { get; set; }

Related

Convert WithOptional to Entity Framework Core(7) equivalent

Im migrating a project from .Net 4.X to .Net 6 and EF 6 to the latest version (version 7 i believe) using Visual Studio 2022.
I've migrated a bunch of configurations but the below im not sure the best way to proceed (the database already exists)
Here is EF6 code
internal class CustomerConfiguration : EntityTypeConfiguration<Customer>
{
public CustomerConfiguration()
{
this.HasMany(e => e.CustomerDocuments)
.WithOptional(e => e.Customer)
.HasForeignKey(e => e.CustomerID);
}
}
In EF 7 i have the code as
internal class CustomerConfiguration : IEntityTypeConfiguration<Customer>
{
public void Configure(EntityTypeBuilder<Customer> builder)
{
builder.HasMany(e => e.CustomerDocuments)
}
}
But i cant find the equivalent for .WithOptional and https://learn.microsoft.com/en-us/ef/core/modeling/relationships?tabs=fluent-api%2Cfluent-api-simple-key%2Csimple-key doesnt really show me any example of how i can configure it although .HasForeignKey seems to exist but i think once WithOptional is resolved it may give some way to convert/use HasForeignKey.
I read WithOptional with Entity Framework Core but then i get confused with if its replacement is HasOne as im already using WithOne (in another Entity configuration) to convert WithRequired (from EF 6)
Anyone know what im missing here or how to convert to the equivalent in EF 7?
In EF Core these are simply separated to WithOne (for relationship cardinality and associated reference navigation property mapping) and IsRequired (whether it required/optional).
So the general conversion of EF6 WithOptional / WithRequired after HasMany / HasOne to EF Core is like
.WithOptional(e => e.Customer)
maps to
.WithOne(e => e.Customer)
.IsRequired(false)
and
.WithRequired(e => e.Customer)
maps to
.WithOne(e => e.Customer)
.IsRequired(true) // or just .IsRequired()
The same applies if you start configuration from the "one" side, i.e. HasOptional / HasRequired become HasOne().With{One|Many}).IsRequired(false|true)

Automapper: mapping RedisValue from StackExchange.Redis StreamEntry to an object strange behavior

I encountered some strange behavior while mapping StreamEntry from StackExchange.Redis library to a C# record. While I found the way to write the mapping to make it work, I still do not understand, why does it work only this way (probably due to limited knowledge of AutoMapper internals). Also, I think this could be an example to anyone who hits this problem itself.
Short introduction:
I was migrating .Net 5 project using StackExchange.Redis & AutoMapper to .Net 6, same time updating all the packages used. Automapper became version 11 and StackExchange.Redis version 2.2.88.
When I ran our unit tests, mapping validation suddenly failed. I didn't change a lot in mappings, replaced only ForAllOtherMembers with ForAllMembers and it was quite strange for me.
The problem itself:
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id)) directive is invalid if src object is StreamEntry. It just throws error "Error mapping types." on validation like if there was no mapping!
Solution:
After some trying around, I've managed to find out that you should use not MapFrom<TSourceMember>(Expression<Func<TSource, TSourceMember>> mapExpression), but MapFrom<TResult>(Func<TSource, TDestination, TResult> mappingFunction) and everything works. So just changing code line above to .ForMember(dest => dest.Id, opt => opt.MapFrom((src, _) => src.Id)) magically fixed everything.
Questions:
Why? I think this is related to how RedisValue is implemented, but I really don't understand why it stopped working in .Net 6 with AutoMapper 11.
To map all members that have string type we use .ForAllMembers(opt => opt.MapFrom(src => src[opt.DestinationMember.Name])) and it still work as it was, however if you try to replace it with .ForAllMembers(opt => opt.MapFrom((src, _) => src[opt.DestinationMember.Name])), it will break.
.Net 6 console example that shows both of issues and correct way to map could be found here. TLDR: Configurations A & C are invalid and B is how it should be done.
These are usage errors. ForAllMembers, as the name indicates, will overwrite your custom config.
Just don't write code like that.

Recreate migration when making a change to the model

I have spent a lot of time writing ADO.NET code recently. I have moved back to EF Core and I am now looking at the config below:
modelBuilder.Entity<PersonSport>().HasKey(sc => new { sc.PersonId, sc.SportId });
modelBuilder.Entity<Sport>()
.ToTable("Sport")
.HasDiscriminator<string>("SportType")
.HasValue<Football>("Football")
.HasValue<Running>("Running");
modelBuilder.Entity<PersonSport>()
.HasOne<Person>(sc => sc.Person)
.WithMany(s => s.PersonSport)
.HasForeignKey(sc => sc.PersonId)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<PersonSport>()
.HasOne<Sport>(sc => sc.Sport)
.WithMany(s => s.PersonSport)
.HasForeignKey(sc => sc.SportId)
.OnDelete(DeleteBehavior.Cascade);
var navigation = modelBuilder.Entity<Person>().Metadata.FindNavigation(nameof(ConsoleApp1.Person.PersonSport));
navigation.SetPropertyAccessMode(PropertyAccessMode.Field);
If I delete a Person or a Sport then the approapriate PersonSport records are deleted because DeleteBehaviour.Cascade is set for OnDelete. If I want to change this to DeleteBehaviour.Restrict, then I have to recreate the migrations and update the database. Why? The reason I ask why is because PersonSportContext.OnModelCreating runs every time I start the program.
I realise this is quite a simple question. I have been away from the ORM for a while and am much more experienced with ADO.NET.
I have spent the last hour or so reading through several similar questions on here, however I have not found the answer to my specific question.
You don't have to use Migrations. It's just a convenient way to ensure that your EF model and database schema are in sync. Some other ways to keep them in sync:
Reverse engineer your model (Scaffold-DbContext or dotnet ef dbcontext scaffold) every time you change the database schema.
Manually make changes to your EF model and database schema at the same time.

Entity Framework issues - appends a "1" to my table name?

I have the following model-first (is that what it's called?) diagram that I have made. I use T4 to generate the classes.
Now, I have a problem that causes Entity Framework to somehow append a "1" to the table name of the DatabaseSupporter entity. The database has been generated from this very model, and nothing has been modified.
I am trying to execute the following line:
_entities.DatabaseSupporters.SingleOrDefault(s => s.Id == myId);
The error I receive when executing that line (along with its inner exception below) is:
An exception of type
'System.Data.Entity.Core.EntityCommandExecutionException' occurred in
mscorlib.dll but was not handled in user code.
Invalid object name 'dbo.DatabaseSupporter1'.
I tried fixing the problem with the following Fluent API code (notice the second line in the function that names the table explicitly to "DatabaseSupporter"), but with no luck.
protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
modelBuilder
.Entity<DatabaseSupporter>()
.HasOptional(f => f.DatabaseChatSession)
.WithOptionalPrincipal(s => s.DatabaseSupporter);
modelBuilder
.Entity<DatabaseSupporter>()
.Map(m =>
{
m.Property(s => s.Id)
.HasColumnName("Id");
m.ToTable("DatabaseSupporter");
});
modelBuilder
.Entity<DatabaseSupporter>()
.HasMany(s => s.DatabaseGroups)
.WithMany(g => g.DatabaseSupporters)
.Map(m =>
{
m.ToTable("DatabaseSupporterDatabaseGroup");
m.MapLeftKey("DatabaseGroups_Id");
m.MapRightKey("DatabaseSupporters_Id");
});
modelBuilder
.Entity<DatabaseGroup>()
.HasRequired(g => g.DatabaseChatProgram)
.WithMany(c => c.DatabaseGroups);
modelBuilder
.Entity<DatabaseGroup>()
.HasRequired(g => g.DatabaseOwner)
.WithMany(o => o.DatabaseGroups);
modelBuilder
.Entity<DatabaseOwner>()
.HasMany(o => o.DatabaseChatSessions)
.WithRequired(o => o.DatabaseOwner);
base.OnModelCreating(modelBuilder);
}
It should be mentioned that the Id property for every entity actually is a Guid.
I am using Entity Framework 6.0.2.
Any ideas?
Edit 1
Here's the generated DatabaseSupporter.cs file containing my DatabaseSupporter entity as requested in the comments.
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Coengage.Data.Entities
{
using System;
using System.Collections.Generic;
public partial class DatabaseSupporter
{
public DatabaseSupporter()
{
this.DatabaseGroups = new HashSet<DatabaseGroup>();
}
public bool IsActive { get; set; }
public string Username { get; set; }
public System.Guid Id { get; set; }
public virtual DatabaseChatSession DatabaseChatSession { get; set; }
public virtual ICollection<DatabaseGroup> DatabaseGroups { get; set; }
}
}
Edit 2
The errors started occuring after I added the many-to-many link between DatabaseSupporter and DatabaseGroup. Before that link, the Fluent code wasn't needed either.
This mapping is incorrect:
modelBuilder
.Entity<DatabaseSupporter>()
.Map(m =>
{
m.Property(s => s.Id)
.HasColumnName("Id");
m.ToTable("DatabaseSupporter");
});
It is kind of 50 percent of a mapping for Entity Splitting - a mapping that stores properties of a single entity in two (or even more) separate tables that are linked by one-to-one relationships in the database. Because the mapping is not complete you even don't get a correct mapping for Entity Splitting. Especially EF seems to assume that the second table that contains the other properties (that are not explicitly configured in the mapping fragment) should have the name DatabaseSupporter1. I could reproduce that with EF 6 (which by the way has added a Property method to configure single properties in a mapping fragment. In earlier versions that method didn't exist (only the Properties method).) Also the one-to-one constraints are not created correctly in the database. In my opinion EF should throw an exception about an incorrect mapping here rather than silently mapping the model to nonsense without exception.
Anyway, you probably don't want to split your entity properties over multiple tables but map it to a single table. You must then replace the code block above by:
modelBuilder.Entity<DatabaseSupporter>()
.Property(s => s.Id)
.HasColumnName("Id");
modelBuilder.Entity<DatabaseSupporter>()
.ToTable("DatabaseSupporter");
The first mapping seems redundant because the property Id will be mapped by default to a column with the same name. The second mapping is possibly also redundant (depending on if table name pluralization is turned on or not). You can try it without this mapping. In any case you shouldn't get an exception anymore that complains about a missing dbo.DatabaseSupporter1.
I have replicated your model exactly as you have listed it and I cannot currently reproduce your issue in the DDL that the EDMX surface emits when Generating Database from Model.
Could you please provide detailed information on exactly how you are going about adding your many-to-many relationship between DatabaseGroup and DatabaseSupporter? You say that you're trying to add the relationship on the edmx surface and NOT through code and it craps on your table name?
I added this thing Many-to-many from DatabaseGroup to DatabaseSupporter
I added this thing Many-to-many from DatabaseSupporter to DatabaseGroup
Can you please provide the following:
Rollback to your codebase prior to adding the many-to-many relationship. Ensure that your EF Fluent API code is not currently in your project.
Generate the DDL from this surface and confirm that it is not being
generated with the name DatabaseSupporters1 (Post the tablename that
it chooses at this stage. DatabaseSupporter or DatabaseSupporters)
Now, right click DatabaseGroup| Add New| Association
Choose DatabaseGroup for the left and DatabaseSupporter for the
right. Confirm that the name of the association that the designer
chooses is DatabaseGroupDatabaseSupporter [Do not create]
Choose DatabaseSupporter for the left and DatabaseGroup for the
right. Confirm that the name of the association that the designer
chooses is DatabaseSupporterDatabaseGroup [Create]
From the edmx surface, right click the many-to-many association just created and click "Show in Model Browser"
Edit your post to include the settings that display.
Also, right click the surface and click "Generate Database from Model."
Edit your post to include the DDL that gets generated. The table
should be named [DatabaseSupporters]
(My first inclination is that it's going to have something to do with your navigation properties, but not entirely sure. I actually had Entity Framework do the same thing to me in a toy project I was working on but I recall it being trivial to correct and I don't recall what the root cause was; I seem to recall it being something about the nav properties)
[Edit]
Wait.....
If I remove the many-to-many that doesn't fix my problem. However,
reverting to before I added the many-to-many fixes it. The exact code
that throws the exception is already shown. If I remove my fluent
mappings entirely, it's not the same exception being thrown (it throws
something about a group and a supporter, and a principal). I have not
tried recreating the model in an empty project - that takes a lot of
time. I already tried searching the EDMX in Notepad for references -
none were found.
(note my added emphasis)
So the DatabaseSupporter1 error showed up after you tried your fluent api patch? Get rid of the patch, add the many-to-many and give us the real error then.
...also, it took me 5 minutes to build this diagram. I wouldn't qualify that as "a lot of time."
I don't have my dev environment here in front of me, but my immediate thoughts are:
FIRST
Your fluent looks ok - but is the plural s in your ID column correct? And no plural (s) on the table names? This would be the opposite of convention.
SECOND
EF will automatically append a number to address a name collision. See similar question here: Why does EntityFramework append a 1 by default in edmx after the database entities?
Any chance you have something hanging around - a code file removed from your solution but still in your build path? Have you tried searching your source folder using windows explorer rather than the visual studio?
modelBuilder
.Entity<DatabaseSupporter>()
.HasMany(s => s.DatabaseGroups)
.WithMany(g => g.DatabaseSupporters)
.Map(m =>
{
m.ToTable("DatabaseSupporterDatabaseGroup");
m.MapLeftKey("DatabaseGroups_Id");
m.MapRightKey("DatabaseSupporters_Id");
});
Left and Right are inversed on Many to Many.
Try this :
modelBuilder
.Entity<DatabaseSupporter>()
.HasMany(s => s.DatabaseGroups)
.WithMany(g => g.DatabaseSupporters)
.Map(m =>
{
m.ToTable("DatabaseSupporterDatabaseGroup");
m.MapLeftKey("DatabaseSupporters_Id");
m.MapRightKey("DatabaseGroups_Id");
});
I think the DatabaseSupporter class created two time
one name is : DatabaseSupporter
another one is : DatabaseSupporter1
The modified changes are stored in DatabaseSupporter1 and mapping to here.
You need to copy the DatabaseSupporter1 class code and past the code to DatabaseSupporter class . then delete this DatabaseSupporter1 class.
I had this issue from renaming tables in the diagram, specifically changing just the capitalization.
If you rename a table by clicking on the header in the diagram, I think it checks the entity set name before trying to change it, sees it exists (even though it's the same entity set), and appends a 1.
However, if you right-click and open the Properties pane and first rename the Entity Set Name, then change the Name second, it won't add the number.
In my case i have two tables in the same database with the same name (2 different schemas(see image)

Fluent NHibernate Many-to-many mapping with auto-generated pk instead of composite key

I'm working on a RoleProvider in .NET, using Fluent NHibernate to map tables in an Oracle 9.2 database.
The problem is that the many-to-many table connecting users and roles uses a primary key generated from a sequence, as opposed to a composite key. I can't really change this, because I'm writing it to be implemented in a larger existing system.
Here is my UserMap:
public UserMap()
{
this.Table("USR");
HasMany(x => x.Memberships).Cascade.All()
.Table("MEMBERSHIP").Inverse().LazyLoad();
HasManyToMany(x => x.Roles)
.Table("USR_ROLE")
.Cascade.SaveUpdate()
.ParentKeyColumn("USR_ID")
.ChildKeyColumn("ROLE_ID")
.Not.LazyLoad();
}
And my RoleMap:
public RoleMap()
{
this.Table("ROLE");
Map(x => x.Description).Column("ROLE_NAME");
Map(x => x.Comment).Column("ROLE_COMMENT");
HasManyToMany(x => x.Users)
.Table("USR_ROLE")
.ParentKeyColumn("ROLE_ID")
.ChildKeyColumn("USR_ID")
.Inverse();
}
Yet, this is giving me the error:
Type 'FluentNHibernate.Cfg.FluentConfigurationException' in assembly 'FluentNHibernate, Version=1.0.0.593, Culture=neutral, PublicKeyToken=8aa435e3cb308880' is not marked as serializable.
Is there a simple fix to allow this HasMayToMany to use my PersistentObjectMap extension? I'm thinking I may have to add a convention for this many-to-many relationship, but I don't know where to start with that, since I've just started using NHibernate and Fluent NHibernate only recently.
I've been working on this problem for a while and I can't seem to find a solution.
Any help would be much appreciated. Thanks.
EDIT: I think I've found a possible solution here: http://marekblotny.blogspot.com/2009/02/fluent-nhbernate-and-collections.html
I'll try the above method of creating an entity and a class map for the linking table and post my findings.
EDIT 2: I created a linking entity as mentioned in the above blog post and downloaded the newest binaries (1.0.0.623).
This helped me discover that the issue was with setting lazy load and trying to add roles to the user object in a completely new session.
I modified the code to move OpenSession to the BeginRequest of an HttpModule as described here. After doing this, I changed my data access code from wrapping the open session in a using statement, which closes the session when it is finished, to getting the current session and wrapping only the transaction in a using statement.
This seems to have resolved the bulk of my issue, but I am now getting an error that says "Could not insert collection" into the USR_ROLE table. And I'm wondering if the above code should work with a UserRoleMap described as:
public UserRoleMap()
{
this.Table("USR_ROLE");
/* maps audit fields id, created date/user, updated date/user */
this.PersistentObjectMap("USR_ROLE");
/* Link these tables */
References(x => x.Role).Column("ROLE_ID");
References(x => x.User).Column("USR_ID");
}
Hibernate's documentation for many-to-many relationship suggests creating an object to maintain a one-to-many/many-to-one, as in an ERD. I'm sure this would be much easier with conventional naming standards, but I have to stick with certain abbreviations and odd (and not always properly-implemented) conventions.
To fix this, I created an Entity, Mapping, and Repository for UserRole. And, instead of HasManyToMany mapping in the User and Role Entities, I have a HasMany mapping. It's a little weird, because I now have:
IList<UserRole> UserRoles {get; protected set;}
and IList<Role> Roles { get{ return UserRoles.Select(u => u.Role).ToList(); } }
This works, however, I'm not 100% sure why this works and the HasManyToMany doesn't.

Categories

Resources