0

I'm having issues updating entities when referencing the same table multiple times in the one entity.

I have two Classes User and Expense. Expense is referencing to the User multiple times:

  • User - Who lodged the Expense
  • ApprovedUser - Who approved
  • ProcessedUser - Who processed
  • ModifiedUser - Who modified the Expense
    public class User
    {
        /// <summary>
        /// User Id
        /// </summary>
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        [Key]
        public string Id { get; set; }

        /// <summary>
        /// Display Name
        /// </summary>
        [Required]
        [Display(Name = "Display Name")]
        public string DisplayName { get; set; }
    }

    public class Expense
    {
        /// <summary>
        /// User Id
        /// </summary>
        [Required]
        [Display(Name = "User Id")]
        public string UserId { get; set; }

        /// <summary>
        /// Linked User
        /// </summary>
        [ForeignKey("UserId")]
        public User User { get; set; }

        /// <summary>
        /// Approved User Id
        /// </summary>
        [Display(Name = "Approved User Id")]
        public string ApprovedUserId { get; set; } = null;

        /// <summary>
        /// Linked Approve User
        /// </summary>
        [ForeignKey("ApprovedUserId")]
        public User ApprovedUser { get; set; }

        /// <summary>
        /// Processed User Id
        /// </summary>
        [Display(Name = "Processed User Id")]
        public string ProcessedUserId { get; set; } = null;

        /// <summary>
        /// Linked Processed User
        /// </summary>
        [ForeignKey("ProcessedUserId")]
        public User ProcessedUser { get; set; }

        /// <summary>
        /// Modified User Id
        /// </summary>
        [Display(Name = "Modified By User Id")]
        public string ModifiedByUserId { get; set; }

        /// <summary>
        /// Linked Modified User
        /// </summary>
        [ForeignKey("ModifiedByUserId")]
        public User ModifiedBy { get; set; }
    }

When i update the field ModifiedByUserId i get this: A referential integrity constraint violation occurred: The property value(s) of 'User.Id' on one end of a relationship do not match the property value(s) of 'Expense.ModifiedByUserId' on the other end.

However if i null the ModifiedByUserId it updates as normal. I have also tried to null the ModifiedBy and set the ModifiedByUserId with the same result.

I've looked at multiple SO posts and spent 12 hours trying to figure out what seems like something that should be so simple but i and can't find anything that's worked.

(I'd prefer to stay away from fluent api if possible.)

Example

Bob and Jim are in the User table and then there's a Expense Bod originally Modified the Expense so ModifiedByUserId is set to Bob's User.Id. I've now edited the Expense so the ModifiedByUserId should now be my User.Id. Nothing changes in the User, just the Expense

Generated SQL

create table [dbo].[Expense] (
    [Id] [int] not null identity,
    [SubmittedDate] [datetime2](7) not null,
    [UserId] [nvarchar](128) not null,
    [ApprovedUserId] [nvarchar](128) null,
    [ProcessedUserId] [nvarchar](128) null,
    [State] [int] not null,
    [ModifiedByUserId] [nvarchar](128) null,
    [LastNotification] [datetime2](7) not null,
    [NextNotification] [datetime2](7) not null,
    [NumberOfNotifications] [int] not null,
    [StopNotifications] [bit] not null,
    [Inserted] [datetime2](7) not null,
    [Updated] [datetime2](7) not null,
    [Deleted] [bit] not null,
    primary key ([Id])
);

create table [dbo].[User] (
    [Id] [nvarchar](128) not null,
    [DisplayName] [nvarchar](max) not null,
    [Department] [nvarchar](max) null,
    [JobTitle] [nvarchar](max) null,
    [Email] [nvarchar](max) not null,
    [TelephoneNumber] [nvarchar](max) null,
    [MobileNumber] [nvarchar](max) null,
    [DownloadedProfileImg] [bit] not null,
    [ManagerId] [nvarchar](128) null,
    [Deleted] [bit] not null,
    primary key ([Id])
);

alter table [dbo].[Expense] add constraint [Expense_ApprovedUser] foreign key ([ApprovedUserId]) references [dbo].[User]([Id]);
alter table [dbo].[Expense] add constraint [Expense_ModifiedBy] foreign key ([ModifiedByUserId]) references [dbo].[User]([Id]);
alter table [dbo].[Expense] add constraint [Expense_ProcessedUser] foreign key ([ProcessedUserId]) references [dbo].[User]([Id]);
alter table [dbo].[Expense] add constraint [Expense_User] foreign key ([UserId]) references [dbo].[User]([Id]);
alter table [dbo].[User] add constraint [User_Manager] foreign key ([ManagerId]) references [dbo].[User]([Id]);

Code

var expense = await ExpenseService.GetExpense(4);
expense.Updated = DateTime.Now;
expense.ModifiedByUserId = "user_id_string";
await ExpenseService.Update(expense);

GetExpense

        public async Task<Expense> GetExpense(int? id)
        {
            var expense = await Expenses.Query()
                .Include(x => x.User)
                .Include(x => x.ModifiedBy)
                .Include(x => x.ApprovedUser)
                .Include(x => x.ProcessedUser)
                .FirstAsync(x => x.Id == id);

            return expense;
        }

Update Expense:

        public async Task<Expense> Update(Expense expense)
        {
            Expenses.Update(expense);
            await Context.SaveAsync();

            return expense;
        }

Repository Update

        public void Update(TEntity entity)
        {
            _dbSet.Attach(entity);
            _context.SetState(entity, EntityState.Modified);
        }
Lee Stevens
  • 472
  • 5
  • 17
  • user.id and ModifiedByUserId do not have same value. sometimes you don't want to fill the ModifiedByUserId then you have to set it with null value. – Amin Saadati Jun 23 '19 at 03:36
  • Hi Amin, i think this is the part i don't understand. I'm setting a new `ModifiedByUserId` because i have updated the entity. I'm saying that, originally the `ModifiedByUserId` was set to `X` and now it needs to be set to `Y` as a different user has edited it. – Lee Stevens Jun 23 '19 at 03:46
  • okay. no problem here . you should check your new user.id and ModifiedByUserId that they have same value or no when you want to update it. first check please – Amin Saadati Jun 23 '19 at 03:54
  • I'm not updating the `User` entity only the `Expense`. The `ModifiedByUserId` should just reference to the specified `User`. So i'm not sure why it's effecting the `User`? For example: You and Me are in the `User` table and then there's a `Expense` you originally Modified the `Expense` so `ModifiedByUserId` is set your `User.Id`. I've now edited the `Expense` so the `ModifiedByUserId` should now be my `User.Id`. Nothing changes in the `User`, just the `Expense`. – Lee Stevens Jun 23 '19 at 04:01
  • okay. we have to way to check other conditions. first : are you sure you have real data in the user table ? (real UserId value , cuz when you savechange it you get this error ) and second is updating the expense without new ModifiedByUserId and see it work or not. (means change on other properties no on ModifiedByUserId ) – Amin Saadati Jun 23 '19 at 04:08
  • Yep, i'm sure there Data in the table. I can update fine, if i don't update the `ModifiedByUserId` as soon as i try to update `ModifiedByUserId` i get the error. – Lee Stevens Jun 23 '19 at 04:10
  • I found a page that can help you too . https://stackoverflow.com/questions/10001189/entity-framework-a-referential-integrity-constraint-violation-on-many-to-many-r?rq=1 – Amin Saadati Jun 23 '19 at 04:12
  • @philipxy, the solution has over 13 projects and god knows how many files, there's no simple way to just cut out that part for debugging. – Lee Stevens Jun 23 '19 at 04:14
  • @AminSaadati, yeah i've seen this post. It didn't help as i said in the OP if i set to null it works as suggested in the post, but i want to set a value not null it. – Lee Stevens Jun 23 '19 at 04:15
  • If you can't instrument your code for debugging it, you can't develop it. Anyway, give what you can. Eg the database state & what is sent to the DBMS. Eg chopping out code localizes bugs. Eg cut & paste code immediately on running & data before & after running. PS Shouldn't `public User ModifiedBy` be `public User ModifiedByUser`? Isn't `Expense.ModifiedByUserId` a string? – philipxy Jun 23 '19 at 04:26
  • @philipxy, does the naming matter from `ModifiedBy` to `ModifiedByUser`? Yes `Expense.ModifiedByUserId` is a string. – Lee Stevens Jun 23 '19 at 04:30
  • 1
    how you update the expense. please edit you post with new information. like your back end-code and everything else that can help us to find a way... – Amin Saadati Jun 23 '19 at 04:43
  • @AminSaadati, i have added code, i'm using EF code first, using repository pattern. – Lee Stevens Jun 23 '19 at 04:49
  • what is your id value? you use GUID in there ? can you change your to int ?and test it with int type ? – Amin Saadati Jun 23 '19 at 05:19
  • It's a string, as in the class in the OP. I'm pulling the users from Azure AD with uses a string as their ID. – Lee Stevens Jun 23 '19 at 05:22
  • Please give the table contents & all SQL code that was run for the update. – philipxy Jun 23 '19 at 05:27
  • @philipxy, how can i give you that i don't generate the SQL – Lee Stevens Jun 23 '19 at 05:28
  • You could start by googling 'entity framework show sql for query that was run site:stackoverflow.com'. Etc. [Eg.](https://stackoverflow.com/q/1412863/3404097) – philipxy Jun 23 '19 at 05:35
  • even the SQL profile (what code you send to database) can help us that. can you qgive us the update query that execute database – Amin Saadati Jun 23 '19 at 05:41
  • Here's the Table and some rows: https://gist.github.com/LeeStevens318/30309aaf91efc0cde97aae12b0639ca2 I have used `Database.Log = s => System.Diagnostics.Debug.WriteLine(s);` in my DB Context but. the update statement never prints. – Lee Stevens Jun 23 '19 at 06:09
  • Please [use text, not images/links, for text--including tables & ERDs.](https://meta.stackoverflow.com/q/285551/3404097) Paraphrase or quote from other text. Use images only for what cannot be expressed as text or to augment text. Images cannot be searched for or cut & pasted. Include a legend/key & explanation with an image. Make your post self-contained. Insert images/links using edit functions. PS Clarify via edits, not comments. – philipxy Jun 23 '19 at 09:22
  • Please do not stop trying to output the update SQL that failed. You should also be able to access debugging your EF calls to the DBMS. Also please output the data actually in the table, not just insert statements. – philipxy Jun 23 '19 at 09:30

0 Answers0