question

SamuelHurni-0289 avatar image
0 Votes"
SamuelHurni-0289 asked JackJJun-MSFT commented

EF Core 6 Update Data direct from an Object, n-n, n-1, 1-1

Hello together


I have some trouble to add a simple update Endpoint to my asp.Net API where I want to update an Entity and also his relations.

I already tried a lot of ways to update the data and the relations in one step, but I had different errors, like tracking error, duplicate key in joining table or no error but the relation was not updated.

So first I tried to update my data using the connected State with the tracking of EF Core. Normaly I want to use the DTO Pattenr with Automapper but to keep it simple I have an example without this step between.

Here is my model configuration of product:

 public class Product
 {
     [Key]
     public int ProductId { get; set; }
     [Required]
     public string Name { get; set; }
     [Required]
     public string Description { get; set; }
     [Required]
     public double Price { get; set; }
    
     public SubCategorie SubCategorie { get; set; }              //Relation n-1 to Table Subcategorie
        
     public ICollection<Extra> Extra { get; set; }               //Relation n-n to Table Extra
        
    
     public DateTime CreatedDate { get; set; } = DateTime.Now;
     public string CreatedBy { get; set; }
     public string UpdatedBy { get; set; }
     public DateTime UpdatedDate { get; set; }
    
    
 }


And here the config of the extra model which is in n-n relation to the product model:

 public class Extra
 {
     [Key]
     public int ExtraId { get; set; }
     [Required]
     public string Name { get; set; }
     [Required]
     public string Tooltip { get; set; }
     [Required]
     public double Price { get; set; }
    
     public ICollection<Product> Products { get; set; }                  //Relation n-n to Table Product
    
     public ICollection<ProductConfig> ProductConfigs { get; set; }      //Relation n-n to Table PrductConfig
    
     public DateTime CreatedDate { get; set; } = DateTime.Now;
     public string CreatedBy { get; set; }
     public string UpdatedBy { get; set; }
     public DateTime UpdatedDate { get; set; }
    
    
 }


and here the onModelCreatin Method in DBContex, where I configure the relations:


 // Product           
         // n-n to Extra
         modelBuilder.Entity<Product>()
            .HasMany<Extra>(e => e.Extra)
            .WithMany(e => e.Products);
         //n-n to Type
         modelBuilder.Entity<Product>()
            .HasMany<ProductType>(e => e.ProductType)
            .WithMany(e => e.Products);
         // n-1 to Subcategorie
         modelBuilder.Entity<Product>()
          .HasOne<SubCategorie>(e => e.SubCategorie)
          .WithMany(e => e.Product);
         // 1-n to productconfig
         modelBuilder.Entity<Product>()
         .HasMany<ProductConfig>(e => e.ProductConfigs)
         .WithOne(e => e.Product);


Here is the example with the connected state. The problem is here that nothing at the relations happened, for example when an extra object is added and comes with the "porductNew" input.


 public async Task<Product> UpdateProduct(int productId, Product productNew)
     {
         try
         {
             if (productId == productNew.ProductId)
             {
                 //valid
                 Product product = await _db.Product.AsNoTracking()
                 .Include(x => x.Extra)
                 .Include(x => x.ProductType)
                 .FirstOrDefaultAsync(x => x.ProductId == productId);                    
                 product = productNew;                  
                 await _db.SaveChangesAsync();
                 return product;
             }
             else
             {
                 //invalid
                 throw new Exception("Id for updating and Id in the Data not match");
             }
         }
         catch (Exception ex)
         {
             throw new Exception(ex.ToString());
         }
     }


When I set the entity State manually to modified I have a tracking error "the istnace could not been tracked because another instance with the same keyvalue..."

So I tried also with the disconnected state schema. For this I use the update Method. There the relations will be added correct, but when i commit the same changes again, EF Core set the state inside the joining table to added than modified

Here is the repository for this pattern:

 public async Task<Product> UpdateProduct(int productId, Product productNew)
     {
         try
         {
             if (productId == productNew.ProductId)
             {
                 //valid
                 Product product = await _db.Product.AsNoTracking()
                 .Include(x => x.SideDishs)
                 .Include(x => x.Extra)
                 .Include(x => x.ProductType)
                 .FirstOrDefaultAsync(x => x.ProductId == productId);
                   
                 product = productNew;
                   
                 var updatedProduct = _db.Product.Update(product);
                  
                 await _db.SaveChangesAsync();
                 return product;
             }
             else
             {
                 //invalid
                 throw new Exception("Id for updating and Id in the Data not match");
             }
         }
         catch (Exception ex)
         {
             throw new Exception(ex.ToString());
         }
     }


Here is the changetracker from EF Core debugging. The Joining table should in this case have the state modified than added because there was no change at the relations. The error of duplicate key in joining table happens:



Extra {ExtraId: 1} Modified
ExtraId: 1 PK
CreatedBy: 'Admin' Modified
CreatedDate: '19.06.2022 09:54:16' Modified
Name: 'zwei Teller' Modified
Price: 0 Modified
Tooltip: 'Das Essen wird auf zwei Teller serviert' Modified
UpdatedBy: Modified
UpdatedDate: '01.01.0001 00:00:00' Modified
ProductConfigs:
Products: [{ProductId: 1}]
Extra {ExtraId: 2} Modified
ExtraId: 2 PK
CreatedBy: 'Admin' Modified
CreatedDate: '19.06.2022 09:55:27' Modified
Name: 'extra scharf' Modified
Price: 0 Modified
Tooltip: 'Gewürzt mit spezieller Chili Paste' Modified
UpdatedBy: Modified
UpdatedDate: '01.01.0001 00:00:00' Modified
ProductConfigs:
Products: [{ProductId: 1}]
ExtraProduct {ExtraId: 1, ProductsProductId: 1} Added
ExtraId: 1 PK FK
ProductsProductId: 1 PK FK
ExtraProduct {ExtraId: 2, ProductsProductId: 1} Added
ExtraId: 2 PK FK
ProductsProductId: 1 PK FK
Product {ProductId: 1} Modified
ProductId: 1 PK
CreatedBy: 'Admin' Modified
CreatedDate: '19.06.2022 10:27:17' Modified
Description: 'Beschreibung Testprodukt' Modified
Name: 'Testprodukt 1' Modified
Price: 15 Modified
SubCategorieId: FK Unknown
UpdatedBy: 'string' Modified
UpdatedDate: '19.06.2022 08:26:45' Modified
ProductConfigs:
SubCategorie:
Extra: [{ExtraId: 1}, {ExtraId: 2}]
ProductType: []


So does anybody have a simple idea or know a documentation, where the update sequence for ef-core6 with all types of relations with external objects for updating is described?






dotnet-entity-framework-core
· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

@SamuelHurni-0289, Welcome to Microsoft Q&A, Please refer to the Microsoft doc sequences to set up a sequence in the model. Also, I suggest that you could split your question to more small questions, it will be better for you to get qucik and useful answer.


0 Votes 0 ·

0 Answers