How to specify the correct ordering of dependent operations when defining entity relationships?

I am trying to execute an Upsert Advertisement object that contains a List<AdImage> . Advertisement contains a foreign key corresponding to the value of User . A User can have zero or more Advertisements , and Advertisement has one or more AdImages .

The upsert error fails:

An error occurred while saving objects that do not display the property foreign key for their relationships. The EntityEntries property will return null because a single object cannot be identified as the source of the exception. Exception handling during saving can be performed easier by exposing the foreign key properties in its object types. See InnerException for details.

Where is the internal shutdown:

It is not possible to determine the actual ordering for dependent operations. Dependencies may exist due to foreign key constraints, requirements model, or store values.

Advertisement is created just like this:

 var ad = new Advertisement { AdImages = new List<AdImage> { new AdImage {Image = model.Image} }, Message = model.Message, Title = model.Title, User = user, }; _aAdAppService.UpsertAdvertisement(ad); 

The objects in question are defined as:

 public class User : AbpUser<Tenant, User> { // AbpUser is a 3rd party class which defines Id as a primary key public string AccessToken { get; set; } public long UserId { get; set; } public virtual List<Advertisement> Advertisements { get; set; } } public class Advertisement : Entity { [Key] public long Id { get; set; } public string Title { get; set; } public string Message { get; set; } public List<AdImage> AdImages { get; set; } public virtual User User { get; set; } } public class AdImage : Entity { [Key] public int Id { get; set; } public string Image { get; set; } public virtual Advertisement Advertisement { get; set; } } 

Here's how relationships are defined:

 protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<User>() .HasMany(u => u.Advertisements) .WithRequired(x => x.User); modelBuilder.Entity<Advertisement>() .HasMany(a => a.AdImages) .WithRequired(x => x.Advertisement); modelBuilder.Entity<AdImage>() .HasRequired(x => x.Advertisement); base.OnModelCreating(modelBuilder); } 

What does the error message mean? I do not see how my relationship is defined incorrectly. How can i solve this?

+6
source share
2 answers

The solution to this was to put an end to my endpoint in UnitOfWork . I do not understand the Entity Framework Scriptures enough to accurately describe the problem or why it worked, but it did.

This is an example of what worked (although slightly different from the above example):

 [UnitOfWork] public async void Post(AdvertisementVM model) { CheckModelState(); try { if (_unitOfWorkManager.Current == null) { using (var mgr = _unitOfWorkManager.Begin()) { await ExecuteMultipleDatabaseCalls(model); await mgr.CompleteAsync(); } } else { await ExecuteMultipleDatabaseCalls(model); } } catch (Exception ex) { throw new HttpException((int)HttpStatusCode.InternalServerError, ex.Message); } } private async Task ExecuteMultipleDatabaseCalls(AdvertisementVM model) { var retailer = _retailerAppService.GetForUser(model.UserId); var ad = new Advertisement { Message = model.Message, Title = model.Title, Retailer = retailer }; await _adAppService.InsertOrUpdate(ad); await _unitOfWorkManager.Current.SaveChangesAsync(); } 

The UnitOfWork attribute is a member of the ASP.NET Boilerplate project and is defined as follows:

Summary: This attribute is used to indicate that the declaration method is atomic and should be considered as a unit of work. A method that has this attribute is intercepted, a database connection is opened, and the transaction starts before the method is called. At the end of the method call, the transaction is committed, and all changes are applied to the database, if there is no exception, otherwise it is rolled back.

Notes: This attribute does not work if there is already a unit of work before calling this method, if so, it uses the same transaction.

+1
source

This is just a comment, but I can not write it in the comments ...

The first time I see an exception

It is not possible to determine the actual ordering for dependent operations. Dependencies may exist due to foreign key constraints, requirements model, or store values.

so I tried to reproduce it.

So I implemented the missing classes and context

 public class Entity {} public class Tenant {} public class AbpUser<T1, T2> {} public Context(DbConnection connection) : base(connection, false) { } public DbSet<Advertisement> Advertisements { get; set; } public DbSet<User> Users { get; set; } public DbSet<AdImage> AdImages { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<User>() .HasMany(u => u.Advertisements) .WithRequired(x => x.User); modelBuilder.Entity<Advertisement>() .HasMany(a => a.AdImages) .WithRequired(x => x.Advertisement); modelBuilder.Entity<AdImage>() .HasRequired(x => x.Advertisement); base.OnModelCreating(modelBuilder); } 

These are the DDL statements created by EF during automatic migration.

 ExecuteNonQuery========== CREATE TABLE [AdImages] ( [Id] int not null identity(1,1) , [Image] text null , [Advertisement_Id] int not null ); ALTER TABLE [AdImages] ADD CONSTRAINT [PK_AdImages_87d4bad2] PRIMARY KEY ([Id]) ExecuteNonQuery========== CREATE TABLE [Advertisements] ( [Id] int not null identity(1,1) , [Title] text null , [Message] text null , [User_UserId] int not null ); ALTER TABLE [Advertisements] ADD CONSTRAINT [PK_Advertisements_5d578c9a] PRIMARY KEY ([Id]) ExecuteNonQuery========== CREATE TABLE [Users] ( [UserId] int not null identity(1,1) , [AccessToken] text null ); ALTER TABLE [Users] ADD CONSTRAINT [PK_Users_5d578c9a] PRIMARY KEY ([UserId]) ExecuteNonQuery========== CREATE INDEX [IX_Advertisement_Id] ON [AdImages] ([Advertisement_Id]) ExecuteNonQuery========== CREATE INDEX [IX_User_UserId] ON [Advertisements] ([User_UserId]) ExecuteNonQuery========== ALTER TABLE [AdImages] ADD CONSTRAINT [FK_AdImages_Advertisements_Advertisement_Id] FOREIGN KEY ([Advertisement_Id]) REFERENCES [Advertisements] ([Id]) ExecuteNonQuery========== ALTER TABLE [Advertisements] ADD CONSTRAINT [FK_Advertisements_Users_User_UserId] FOREIGN KEY ([User_UserId]) REFERENCES [Users] ([UserId]) 

So, actually everything is as expected.

And here is the test I tried

 public static void Run(DbConnection connection) { var ad = new Advertisement { AdImages = new List<AdImage> { new AdImage {Image = "MyImage"} }, Message = "MyMessage", Title = "MyTitle", User = new User() }; using (Context context = new Context(connection)) { context.Advertisements.Add(ad); context.SaveChanges(); } } 

It triggered these queries in the database

 ExecuteDbDataReader========== insert into [Users]([AccessToken]) values (null); select [UserId] from [Users] where [UserId] = @@identity ExecuteDbDataReader========== insert into [Advertisements]([Title], [Message], [User_UserId]) values (@p0, @p1, @p2); select [Id] from [Advertisements] where [Id] = @@identity @p0 = MyTitle @p1 = MyMessage @p2 = 1 ExecuteDbDataReader========== insert into [AdImages]([Image], [Advertisement_Id]) values (@p0, @p1); select [Id] from [AdImages] where [Id] = @@identity @p0 = MyImage @p1 = 1 

Your model is just perfect :)

So the problem is elsewhere. It can be in code around, i.e. - Where do model and user come from? The same context that you use in Upsert or in another context?
- What are you doing at Upsert? Can you link some links (from model to a new object)?
- other missing classes (those that I left empty)?

+1
source

All Articles