2

I want to implement a change log as advised in Dev Express XAF T474899

I am using the security system generated by the XAF new solution wizard

I have defined some business objects to store the change log information.

One of these objects stores a link to the user

public virtual User User { get; set; }

On generating the code migration I am surprised to see the Up() method add the following

RenameTable(name: "dbo.UserRoles", newName: "RoleUsers");
DropPrimaryKey("dbo.RoleUsers");
AddPrimaryKey("dbo.RoleUsers", new[] { "Role_ID", "User_ID" });

On another occasion I found the following in an Up()

RenameTable(name: "dbo.EventResources", newName: "ResourceEvents");
// lots of other stuff
 DropPrimaryKey("dbo.ResourceEvents");
 AddPrimaryKey("dbo.ResourceEvents", new[] { "Resource_Key", "Event_ID" });

On both occasions the code that creates the entities is a Dev Express libary.

I have cross posted this question to Dev Express Support

The Dev Express business objects are defined in DevExpress.Persistent.BaseImpl.EF;

My DbContext context refers to them as

public DbSet<Role> Roles { get; set; }
public DbSet<User> Users { get; set; }

The meta data for Role shows enter image description here

The meta data for User shows enter image description here

My own business classes contain

    namespace SBD.JobTalk.Module.BusinessObjects
{
    [NavigationItem("Configuration")]
    [DisplayName("Staff")]
    [DefaultProperty("Summary")]
    [ImageName("BO_Employee")]
    [Table("Staff")]
    public class Staff : BasicBo
    {
        public Staff()
        {
            Person = new Person();
        }
        public virtual Person Person { get; set; }

        [StringLength(100, ErrorMessage = "The field cannot exceed 100 characters. ")]
        [scds.Index("IX_Staff_UserName", 1, IsUnique = true)]
        public string UserName { get; set; }
        [NotMapped]
        public string Summary => $"{Person.FirstName} {Person.LastName}";

        //public virtual User User { get; set; }
    }
}

public abstract class BasicBo : IXafEntityObject  
{
    [Browsable(false)]
    [Key]
    public virtual int Id { get; set; }
    public virtual void OnCreated()
    {

    }
      public virtual void OnSaving()
    {
    }

    public virtual void OnLoaded()
    {
    }
}

If I un-comment the code to have the User property inside Staff, and generate a migration, the migration Up is

 public override void Up()
    {
        RenameTable(name: "dbo.UserRoles", newName: "RoleUsers");
        DropPrimaryKey("dbo.RoleUsers");
        AddColumn("dbo.Staff", "User_ID", c => c.Int());
        AddPrimaryKey("dbo.RoleUsers", new[] { "Role_ID", "User_ID" });
        CreateIndex("dbo.Staff", "User_ID");
        AddForeignKey("dbo.Staff", "User_ID", "dbo.Users", "ID");
    }

[Update] Interestingly there are more Dev Express tables than I first thought. The primary keys are Identity.

enter image description here I think am using Standard Authentication created before Dev Express added the Allow/Deny ability (V16.1)

[Update] When I create a new project with the above settings, here is the DbContext.

using System;
using System.Data;
using System.Linq;
using System.Data.Entity;
using System.Data.Common;
using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;
using System.ComponentModel;
using DevExpress.ExpressApp.EF.Updating;
using DevExpress.Persistent.BaseImpl.EF;
using DevExpress.Persistent.BaseImpl.EF.PermissionPolicy;

namespace XafApplication1.Module.BusinessObjects {
    public class XafApplication1DbContext : DbContext {
        public XafApplication1DbContext(String connectionString)
            : base(connectionString) {
        }
        public XafApplication1DbContext(DbConnection connection)
            : base(connection, false) {
        }
        public XafApplication1DbContext()
            : base("name=ConnectionString") {
        }
        public DbSet<ModuleInfo> ModulesInfo { get; set; }
        public DbSet<PermissionPolicyRole> Roles { get; set; }
        public DbSet<PermissionPolicyTypePermissionObject> TypePermissionObjects { get; set; }
        public DbSet<PermissionPolicyUser> Users { get; set; }
        public DbSet<ModelDifference> ModelDifferences { get; set; }
        public DbSet<ModelDifferenceAspect> ModelDifferenceAspects { get; set; }
    }
}
Kirsten
  • 15,730
  • 41
  • 179
  • 318
  • 1
    Cross posted to Dev Express https://www.devexpress.com/Support/Center/Question/Details/T486359 – Kirsten Feb 23 '17 at 21:43
  • 1
    Show the User class. Is that Identity? Context and DbSets might help as well. – Steve Greene Mar 04 '17 at 17:00
  • Thanks @SteveGreene I have updated the question – Kirsten Mar 04 '17 at 21:29
  • 1
    Migrations are based on a diff from the prior code migration. Is this the first migration or are there preceding migrations that were applied? Did Dev Express update it's models between? Is the actual table in the database called UserRole or RoleUsers? – Steve Greene Mar 06 '17 at 02:47
  • Good points which led me to some discoveries. I have updated my question and also the question at Dev Express. Another thought occurs to me that it could be my fault for deleting some migrations. As mentioned in http://stackoverflow.com/questions/42568212/generate-missing-migrations-so-i-can-update-an-old-database-structure still that would not explain why a different namespace is now being used. – Kirsten Mar 06 '17 at 04:20
  • I tried to repeat the problem using a new XAF project and adding my Staff class with the User property. I could not repeat the problem, so I think you are on the right track about some upgrade going awry. – Kirsten Mar 06 '17 at 04:30
  • 1
    If you are confident in your model, you can always just comment out the up() code and apply it. Then you won't be asked again. – Steve Greene Mar 06 '17 at 14:02
  • looking at http://forums.devart.com/viewtopic.php?f=30&t=27730 – Kirsten Mar 09 '17 at 02:10
  • seems to me that Code first can't "know" which of 2 names to use (RoleUsers or UserRoles) unless there is fluent mapping in the OnModelCreating method: – Kirsten Mar 09 '17 at 03:41
  • @SteveGreene could you answer this so I can award to points? I am thinking the answer is along the lines of my last comment. – Kirsten Mar 10 '17 at 18:39

1 Answers1

1

OK, I will take a stab :) Your Up() code is trying to rename the table UserRoles to RoleUsers. This means you have a prior migration where UserRoles was the table name - probably from your DevEx stuff. This could happen if they changed their models in an upgrade. The current models are expecting RoleUsers etc. so you need to get there.

So first option is let the migration do the renaming to match the underlying model. I assume this didn't work or causes other issues?

You might be able to 'fool' entity framework into using the old tables with fluent code or annotations, but if it has new columns or relationships that won't work.

What I would do is this:

1) Create a new test project with the same references you had and copy your context and DbSets. Point the connection string to a new database.

2) Add a migration and script it out: update-database -Script.

3) Examine this script a use it to create the objects needed in your database. Migrate data from the old tables to new if needed.

4) Remove the old tables

5) In your actual project add a migration to resync your models: add-migration SyncDevExUpdate -IgnoreChange, update-database

Now you will have the tables your models expect.

Steve Greene
  • 12,029
  • 1
  • 33
  • 54
  • Revisiting this, the problem was because I had set up a User Navigation property in my Staff class. – Kirsten Jun 13 '20 at 07:24