BUG: Entity Framework Power Tools Fails to Generate Designer - entity-framework

Entity Framework 6.1 using Power Tools 4 generates an error when using the command:
View Entity Data Model (Read Only) on the context.
The error:
An error occurred while trying to build the model for Context. See the output window for details.
The output window basically states:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.MissingMethodException: Method not found: 'xyz.domain.User xyz.domain.DomainBase.get_ModifiedBy()'
* CRITICAL * The power tools are also caching the schema and do NOT update with changes! ***
Example:
Create a base class:
public abstract class DomainBase {
public DateTime DateCreated { get; set; }
public DateTime DateModified { get; set; }
public User CreatedBy { get; set; }
public string CreatedByName { get; set; }
public User ModifiedBy { get; set; }
public string ModifiedByName { get; set; }
}
Create a class that inherits from the base class:
public class User : DomainBase {
public int UserId { get; set; }
public string Username { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Password { get; set; }
public string Salt { get; set; }
public string Pin { get; set; }
}
Create Base Mapping:
public class DomainBaseConfig<TEntity> : EntityTypeConfiguration<TEntity>
where TEntity : DomainBase {
public DomainBaseConfig() {
this.HasOptional(c => c.ModifiedBy).WithOptionalDependent()
.Map(m => m.MapKey("ModifiedById"));
this.HasOptional(c => c.CreatedBy).WithOptionalDependent()
.Map(m => m.MapKey("CreatedById"));
this.Property(t => t.CreatedByName).HasMaxLength(FieldMaxSize.FullName).IsRequired();
this.Property(t => t.ModifiedByName).HasMaxLength(FieldMaxSize.FullName).IsRequired();
this.Property(t => t.DateCreated).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
this.Property(t => t.DateModified).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
}
}
Created User class mapping:
public UserConfig() {
this.ToTable("Users");
this.HasKey(c => c.UserId);
this.Property(t => t.FirstName).HasMaxLength(FieldMaxSize.FirstName).IsRequired();
this.Property(t => t.LastName).HasMaxLength(FieldMaxSize.LastName).IsRequired();
this.Property(t => t.Password).HasMaxLength(FieldMaxSize.Password).IsRequired();
this.Property(t => t.Pin).HasMaxLength(FieldMaxSize.Pin).IsRequired();
this.Property(t => t.Salt).HasMaxLength(FieldMaxSize.Salt).IsRequired();
this.Property(t => t.Username).HasMaxLength(FieldMaxSize.Username).IsRequired().HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute("IX_Username", 1) { IsUnique = true }));
}
When trying to view the model, the error seems to be related to the base class referring to the parent class where the parent requires the base (they reference each other) and the designer doesn't like this, but EF handles it just fine.
PROOF: If I remove the references to "User" in the base class, the designer WILL work (badly)... NOTE... I do get it to work by removing both base class properties referencing the User class and their associated mappings... BUT... the designer STILL MODELS THEM!
So, I remove the User properties (ModifiedBy and CreatedBy) in the base class and I also remove the associated mappings, then the designer builds a graphic representations of the schema ... BUT... it still includes the properties I just commented out (they are clearly cached somewhere)!
PLEASE!
(1) Correct the designer so it doesn't crash on valid schema as provided in the sample
(2) Fix the caching problem with the designer so that it NEVER builds schema for the designer on old/stale code!
Based on this example, the Power Tools designer is completely unreliable as it can clearly build a model that DOES NOT match actual code/schema.

For entity framework >= 6 you need to use Entity framework designer tools http://www.microsoft.com/en-au/download/details.aspx?id=40762

Related

EF Core - One to many relationship with additional navigation property of same dependent entity type

I'm having trouble configurating my relationships in EF Core. I've been greeted with the following exception -
Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other
FOREIGN KEY constraints
I've trimmed back the entities for this post, but both of these entities have their own table.
public class ApplicationSetupTest
{
public Guid Id { get; set; }
public Guid SchemeId { get; set; }
public string Description { get; set; }
public Guid LatestVersionId { get; set; }
public ApplicationSetupVersionTest LatestVersion { get; set; }
public ICollection<ApplicationSetupVersionTest> VersionHistory { get; set; }
}
public class ApplicationSetupVersionTest
{
public Guid Id { get; set; }
public Guid SetupId { get; set; }
public string Data { get; set; }
public string AuditComment { get; set; }
public Guid PreviousVersionId { get; set; }
}
The ApplicationSetupTest class effectively defines static data with a LatestVersionId that is the key for navigation property LatestVersion.
The ApplicationSetupVersionTest class is the versioned/audited data. Each one of these has a SetupId to link it back to the ApplicationSetupTest to which is refers.
I added the VersionHistory property purely for this post to demonstrate that there could be multiple ApplicationSetupVersionTest on every ApplicationSetupTest. I haven't added an ApplicationSetupTest on the ApplicationSetupVersionTest as this isn't something I expect to need.
My configuration for ApplicationSetupTest is then as follows:
public class ApplicationSetupEntityConfiguration : IEntityTypeConfiguration<ApplicationSetupTest>
{
public void Configure(EntityTypeBuilder<ApplicationSetupTest> builder)
{
builder.Property(t => t.SchemeId).IsRequired();
builder.Property(t => t.Description).IsRequired();
builder.Property(t => t.LatestVersionId).IsRequired();
builder.HasMany(t => t.VersionHistory)
.WithOne()
.HasForeignKey(t => t.SetupId)
.IsRequired();
builder.HasOne(t => t.LatestVersion)
.WithOne()
.HasForeignKey<ApplicationSetupTest>(t => t.LatestVersionId)
.OnDelete(DeleteBehavior.NoAction)
.IsRequired();
builder.HasOne<Scheme>()
.WithMany()
.HasForeignKey(t => t.SchemeId)
.IsRequired();
}
}
The HasMany -> WithOne on VersionHistory is there to define that when I delete a setup, I should delete all version entities.
I assume the second configuration is therefore the area to change. The OnDelete(NoAction) was added following Google searches and I also tried removing the IsRequired() as well as making the LatestVersionId nullable.
I am looking to configure the second relationship so that the LatestVersion property can be included on query.
Any thoughts out there on how to configure such a relationship? Or am I doing something that you wouldn't recommend?
(I will refer to the models as Setup and Version for simplicity).
With your one-to-many configuration -
builder.HasMany(t => t.VersionHistory)
.WithOne()
.HasForeignKey(t => t.SetupId)
.IsRequired();
you have declared Setup as the principal end, and Version as the dependent end, which is correct.
But then you have a LatestVersionId foreign key in Setup, referencing to Version, and configuration of the one-to-one relationship -
builder.HasOne(t => t.LatestVersion)
.WithOne()
.HasForeignKey<ApplicationSetupTest>(t => t.LatestVersionId)
.OnDelete(DeleteBehavior.NoAction)
.IsRequired();
trying to configure Setup as the dependent end and Version as the principal end. I'm sure you can see the contradiction.
With the following simplified models -
public class Setup
{
public Guid Id { get; set; }
public string Description { get; set; }
public Version LatestVersion { get; set; }
public ICollection<Version> VersionHistory { get; set; }
}
public class Version
{
public Guid Id { get; set; }
public string Data { get; set; }
// not nullable - every Version must belong to a Setup
public Guid SetupIdHistory { get; set; }
// nullable - not every Version is a latest version
public Guid? SetupIdLatest { get; set; }
}
you can configure them correctly to represent your relationships as -
public void Configure(EntityTypeBuilder<Setup> builder)
{
builder.HasMany(p => p.VersionHistory)
.WithOne()
.HasForeignKey(p => p.SetupIdHistory)
.OnDelete(DeleteBehavior.Cascade) // not required, cascading is default
.IsRequired();
builder.HasOne(p => p.LatestVersion)
.WithOne()
.HasForeignKey<Version>(p => p.SetupIdLatest)
.OnDelete(DeleteBehavior.NoAction)
.IsRequired(false);
}
If you choose not to have a foreign key for the one-to-many relationship, EF will create a nullable one for you and manage the relationship at model level with a shadow property. But for the one-to-one relationship, you must define a foreign key.
public class Version
{
public Guid Id { get; set; }
public string Data { get; set; }
// nullable - not every Version is a latest version
public Guid? SetupId { get; set; }
}
public void Configure(EntityTypeBuilder<Setup> builder)
{
builder.HasMany(p => p.VersionHistory)
.WithOne()
.OnDelete(DeleteBehavior.Cascade)
.IsRequired(); // this will have no effect, the FK will be nullable
builder.HasOne(p => p.LatestVersion)
.WithOne()
.HasForeignKey<Model.Version>(p => p.SetupId)
.OnDelete(DeleteBehavior.NoAction)
.IsRequired(false);
}

Mapping same collection with two Navigation Properties

I have the following model
public class Locale
{
public int Id { get; set; }
public ICollection<Localization<Locale>> Localizations { get; set; }
}
public class Localization<T>
{
public int Id { get; set; }
public Locale Locale { get; set; }
public string DisplayName { get; set; }
public T Entity { get; set; }
}
In this case, I want to be able to localize any entity, include the localization itself (ie: for places where we show available languages in the users language ).
I have this working in NHibernate, but I need to move to EF. The issue arises when I want to use the fluent API to map it as follows.
modelBuilder.Entity<Locale>()
.HasMany(x => x.Localizations)
.WithRequired(x => x.Locale)
.Map(x => x.MapKey("LocaleId"));
This works, but then I need to map the entity itself.
Doing this overrides the previous map.
modelBuilder.Entity<Locale>()
.HasMany(x => x.Localizations)
.WithRequired(x => x.Entity)
.Map(x => x.MapKey("EntityId"));
Doing it this way throws an error on either field (I've also tried making a sub class of Localization called LocaleLocalization, with the same result).
modelBuilder.Entity<Localization<Locale>>()
.HasRequired(x => x.Entity)
.WithMany()
.Map(x => x.MapKey("LCIDLocale"))
The Error
The navigation property "Entity" is not a declared property on type
Localization. Verify that it has not been explicitly excluded from the model
and that it is a valid navigation property.
The solution is that I need to map two collections, one representing the collection of Localizations for this Locale, and one representing the collection of other Locales which are localized into this locale.
ICollection<Localizations> MyLocalizations { get; set; }
ICollection<Localizations> LocalesLocalizedByMe { get; set; }

Configure a one directional relationship in entity framework

I have a Model
HUBS -< SECTIONS
sections are a tree hierarchy but they all belong to a hub (there is another table managing the hierarchy as one section can appear twice in the tree)
A hub should also have a root section, so on my hub entity I have:
public partial class Hub
{
public Hub()
{
this.Sections = new List<Section>();
}
public int HubId { get; set; }
public string Name { get; set; }
public virtual ICollection<Section> Sections { get; set; }
public int RootSectionId { get; set; }
public virtual Section RootSection { get; set; }
}
If I don't set an mapping as per:
public class HubMap : EntityTypeConfiguration<Hub>
{
public HubMap()
{
// Primary Key
this.HasKey(t => t.HubId);
// Table & Column Mappings
this.ToTable("Hubs");
this.Property(t => t.HubId).HasColumnName("HubId");
this.Property(t => t.Name).HasColumnName("Name");
// Relationships
this.HasRequired(t => t.Site)
.WithMany(t => t.Hubs)
.HasForeignKey(d => d.SiteId);
}
}
I get an error about not finding RootSection_SectionId column. Now I could just rename the column to match, but in the interests of my understanding of EF mapping, I'd like to be able to specify they column, which is "RootSectionId"
What would I need to include in the mapping file to map this field?
Something like :
this.HasRequired(t => t.RootSection)
.WithMany()
.HasForeignKey(d => d.RootSectionId);

Entity Framework Code First - Navigation property on Composite Primaty Key

Firebird 2.5
Entity Framework 5
FirebirdClientDll 3.0.0.0
Hi, I'm trying to access my legacy database with the Entity Framework (Code First).
I got the problem that the database does not use foreign keys...
public class CUSTOMERS
{
public int CUSTOMERID { get; set; }
public string NAME{ get; set; }
}
public class INVOICES
{
public int INVOICEID{ get; set; }
public int CUSTOMERID{ get; set; }
public virtual CUSTOMERS CUSTOMERS { get; set; }
}
public class INVOICEContext : DbContext
{
public DbSet<CUSTOMERS> CUSTOMERS{ get; set; }
public DbSet<INVOICES> INVOICES{ get; set; }
public INVOICEContext(DbConnection connectionString) : base(connectionString, false)
{
Database.SetInitializer<INVOICEContext>(null);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
/*modelBuilder.Entity<INVOICES>().HasRequired(b => b.CUSTOMERS)
.WithMany()
.Map(p => p.MapKey("INVOICEID"));*/ //Doesn't work because INVOICEID is defined
modelBuilder.Entity<INVOICES>().HasKey(a => new { a.INVOICEID, a.CUSTOMERID});
modelBuilder.Entity<CUSTOMERS>().HasKey(a => new { a.CUSTOMERID });
base.OnModelCreating(modelBuilder);
}
}
Normally I could remove the property CUSTOMERID from the class INVOICES, but in this case it is part of the primary key...
I found many threads which suggested to use IsIndependent, but it seems to be removed from the Entity Framework 5 (or 4.1).
I hope you can understand my poor English and maybe give me a hint what I'm doing wrong ^^
I don't know what you mean with "the database does not use foreign keys". So, maybe the following is not the answer you are looking for. But I'd say that you can use your relationship mapping that is commented out in your code if you replace ...MapKey... by HasForeignKey and use CUSTOMERID instead of INVOICEID as the foreign key property:
modelBuilder.Entity<INVOICES>()
.HasRequired(b => b.CUSTOMERS)
.WithMany()
.HasForeignKey(b => b.CUSTOMERID);
The model and the rest of the mapping is fine in my opinion. Your relationship is an identifying relationship (that means that the foreign key is part of a composite primary key) which is a valid mapping with Entity Framework.
Try this ...
modelBuilder.Entity<INVOICES>()
.HasRequired(i => i.CUSTOMERS)
.WithMany()
.HasForeignKey(i => i.CUSTOMERID);

One to many relationship error

I have the following model, but I keep getting an error:
Unhandled Exception: System.InvalidOperationException: A relationship
multiplici ty constraint violation occurred: An EntityReference can
have no more than one r elated object, but the query returned more
than one related object. This is a no n-recoverable error.
public class Tournament
{
public long TournamentId { get; set; }
public string Title { get; set; }
public virtual User CreatedBy { get; set; }
}
public class User
{
public int UserId { get; set; }
}
modelBuilder.Entity<Tournament>()
.HasRequired(t => t.CreatedBy)
.WithOptional()
.Map(c => c.MapKey("CreatedById")); // correct column name
Your model fluent configuration entry is incorrect. Change it as follows
modelBuilder.Entity<Tournament>()
.HasRequired(t => t.CreatedBy)
.WithMany()
.Map(c => c.MapKey("CreatedById")); // correct column name
You'll have better luck managing Foreign keys if you modify you model a bit:
public class Tournament
{
public long TournamentId { get; set; }
public string Title { get; set; }
public virtual int CreatedById {get;set;}
public virtual User CreatedBy { get; set; }
}
and your mapping would look more like this:
modelBuilder.Entity<Tournament>()
.HasRequired(t => t.CreatedBy)
.WithMany()
.HasForeignKey(t => t.CreatedById); // correct column name
This way, when you create a new Tournament Entity you need only pass in the CreatedById and not the entire User object.
This can also happen if you have lazy loading enabled and not specifying all the navigation properties as Overridable (C# Virtual).