EF Core 6直接从对象,NN,N-1,1-1更新数据

发布于 2025-02-08 18:51:46 字数 5997 浏览 3 评论 0原文

我很难将简单的更新端点添加到我的ASP.NET API中,我想更新实体以及他的关系。

我已经尝试了很多方法来在一个步骤中更新数据和关系,但是我有不同的错误,例如跟踪错误,连接表中的重复键或没有错误,但没有更新关系。

因此,首先,我尝试使用EF Core的跟踪使用连接状态更新数据。通常,我想将DTO Pattenr与AutoMapper一起使用,但为了保持简单,我有一个示例,没有这一步骤。

这是我对产品的模型配置:

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; }


}

andher与产品模型有关的额外模型的配置

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; }


}

以及dbContex中的onmodeLcreatin方法,我在这里配置了

      // 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);

此关系是与连接状态的示例。问题在这里,关系中没有任何事情发生,例如添加额外的对象并带有“ porductNew”输入时。

 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());
        }
    }

当我将实体状态手动设置为修改时,我会有一个跟踪错误:“无法跟踪ISTNACE,因为另一个具有相同键值的实例……”

因此,我也尝试使用断开的状态架构。为此,我使用更新方法。那里的关系将是正确的,但是当我再次提交相同的更改时,EF核心将加入表中的状态设置为添加了

此模式的存储库:

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());
        }
    }

这是EF Core Debugging的Changetracker。在这种情况下,加入表应具有比添加的状态修改的,因为关系没有变化。加入表中重复键的错误发生了:

extra {extraid:1}修改后的

Extraid:1 pk

createby:'admin'修改了

createddate:'19 .06.2022 09:54:16'修改

名称:'zwei Teller'修改

价格:0修改

工具提示:'das essen wird auf zwei teller serviert'

修改更新:修改

:'01 .01.0001 00:00:00:00'修改

productsconfigs

:[{productid:1}

]

更新 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'改进的

产品configs:

产品:[{progucatid:1}]

外{extraid:1,productsProductId:1}添加了添加

:1 pk fk fk fk

productsproductid:1 pk

fk fk fk flk product offroductID {extraid {extract {extract offer:2,添加了product productuctid:1}

Extraid:2 PK FK

ProductsProductID:1 PK FK

产品{propartiD:1}修改的

productid:1 pk

createby:'admin'修改

createDate:'19 .06.2022 10:27:17'修改

描述:'beschreibung testprodified'修改后的

名称:' TestProdukt 1'修改

价格:15修改后的

子类别:fk未知

更新:'string'修改后的

更新date:'19 .06.2022 08:26:45'修改

productConfigs:

subcategorie:subcategorie

:subcategorie:extra

productType:[]

因此,有人描述了EF-Core6的更新顺序具有与外部对象进行更新的所有类型的EF-Core6更新顺序?

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; }


}

Andher 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

寄居者 2025-02-15 18:51:47

当您找到数据并且数据将被修改时,您不应使用asnotracking()方法,请阅读有关跟踪与无跟踪查询

public async Task<Product> UpdateProduct(int productId, Product productNew)
{
    try
    {
        Product product = await _db.Product
                                .Include(x => x.SideDishs)
                                .Include(x => x.Extra)
                                .Include(x => x.ProductType)
                                .FirstOrDefaultAsync(x => x.ProductId == productId);
        if (productId == productNew.ProductId && product != null)
        {
            //valid
            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 you are finding the data and the data will be modified, you should not use the AsNoTracking() method, please read more about Tracking vs. No-Tracking Queries.

public async Task<Product> UpdateProduct(int productId, Product productNew)
{
    try
    {
        Product product = await _db.Product
                                .Include(x => x.SideDishs)
                                .Include(x => x.Extra)
                                .Include(x => x.ProductType)
                                .FirstOrDefaultAsync(x => x.ProductId == productId);
        if (productId == productNew.ProductId && product != null)
        {
            //valid
            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());
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文