为了账号安全,请及时绑定邮箱和手机立即绑定

如何在EF Core中实现添加相关数据的方法?

如何在EF Core中实现添加相关数据的方法?

C#
慕桂英546537 2022-11-21 16:02:08
如何实现添加相关数据的方法EF core?需要将哪些对象提交给 add 方法,它应该返回什么?我需要在数据库中添加相关数据,例如: {        "productId": 0,        "number": "xxx",        "amount": 5.65,        "primeCost": 20.33,        "productTypeId": 0,        "parameters": [            {                "id": 0,                "name": "Type",                "value": null            },            {                "id": 3,                "name": "steel grade",                "value": "CK45"            },            {                "id": 4,                "name": "diameter",                "value": "40"            }        ]    }这些是我的模型类:public class Product //: BaseObject{    public int Id { get; set; }    public string Name { get; set; }    public string Number { get; set; }    public double Amount { get; set; }    public double PrimeCost { get; set; }    [ForeignKey("ProductTypeId")]    public int  ProductTypeId {  get; set; }    public virtual ProductType ProductType { get; set; }    public ICollection<ProductParameter> ProductParameters { get; set; } = new List<ProductParameter>();}public class ProductType //: BaseObject{       public int Id { get; set; }    public string NameType { get; set; }    public ICollection<Parameter> Parameters { get; set; } = new List<Parameter>();    public ICollection<Product> Products { get; set; } = new List<Product>();} public class Parameter //: BaseObject{    public int Id { get; set; }    public string Name { get; set; }    [ForeignKey("ProductTypeId")]    public int ProductTypeId { get; set; }    public ProductType ProductType { get; set; }    public ICollection<ProductParameter> ProductParameters { get; set; } = new List<ProductParameter>();} public class ProductParameter //: BaseObject{    public int Id { get; set; }    public int ProductId { get; set; }    public virtual Product Product { get; set; }    public int ParameterId { get; set; }    public virtual Parameter Parameter { get; set; }    public string Value { get; set; }}
查看完整描述

1 回答

?
守着一只汪

TA贡献1872条经验 获得超3个赞

您的方法期望返回一个 IEnumerable,但您只返回传入的单个 Product DTO。


签名应该是:


public async Task<ProductDTO> AddProducts(ProductDTO ProductDTO, List<ParameterDTO> ParameterDTO)

鉴于 ProductDTO 具有 ParameterDTO 的集合,是否还需要第二个参数?(看起来它会发送两次参数)


根据您的实体定义,我发现了一些问题:


[ForeignKey("ProductTypeId")]

public int  ProductTypeId {  get; set; }

public virtual ProductType ProductType { get; set; }

应该


[ForeignKey("ProductType")] // FK to the reference property.

public int  ProductTypeId {  get; set; }

public virtual ProductType ProductType { get; set; }

所有导航属性(例如集合和产品类型)都应声明为虚拟的,否则您将获得不一致的行为。如果需要,声明为虚拟的将可以访问延迟加载,其他将保留为#null。


Product 和 Parameter 都不应该引用 ProductType,据我所知,它可能应该只引用 Product 以避免非规范化问题。(具有不同 ProductTypes 集的参数的产品。)


在处理导航属性时,我建议从实体中删除 FK 属性并使用映射 (EF6)/阴影属性。(英孚核心)


例如:


 public class ProductParameter 

{

    public int Id { get; set; }


    public virtual Product Product { get; set; } // No ProductId/ParameterId

    public virtual Parameter Parameter { get; set; }


    public string Value { get; set; }

}


modelBuilder.Entity<Product>()

    .HasMany(x => x.ProductParameters)

    .WithOne(x => x.Product)

    .HasForeignKey("ProductId"); // Sets up a shadow property.

映射 FK 的问题在于有 2 个真实来源供参考。ProductParameter.ProductId 与 ProductParameter.Product.Id。通常这些将指向相同的值,但代码可能依赖于一条路径而不是另一条路径,如果只更改一条路径而不更改另一条路径,则会导致一致性错误。


谨慎使用异步操作。如果您通过 ID 或任何其他相对快速的操作拉回单个记录,请不要使用异步,因为注册延续会产生性能成本。(更快地进行同步调用)异步适用于预计需要一段时间的操作。(即超过一秒)


最后,该代码可能有效,但它没有很好地利用 EF,单独设置所有这些实体,并且您通常不希望多次调用 SaveChanges 以确保数据一起提交或根本不提交(如果有)问题。


   var EntryProduct = _context.Products.Find(ProductDTO.ProductId);


    if (EntryProduct != null)

        return ProductDTO;


    var product = new Product

    {

        Id = ProductDTO.ProductId,

        Number = ProductDTO.Number,

        Amount = ProductDTO.Amount,

        PrimeCostEUR = ProductDTO.PrimeCostEUR,

    };


    var parameterIds = ParameterDTO.Select(x => x.Id).ToList();

    var parametersToAdd = context.Parameters

        .Where(x => parameterIds.Contains(x.ParameterId))

        .Select(x => new ProductParameter

        {

            Product = product,

            Parameter = x

        }).ToList();


    product.ProductParameters.AddRange(parametersToAdd);

    await _context.SaveChangesAsync();


    return ProductDTO;

我不建议为 DbContext (_context) 使用模块级变量,因为上下文应该是短暂的,以帮助避免一个工作流打算保存而其他代码可能不会保存的潜在问题。如果它由 IoC 容器注入并限定为与请求匹配的生命周期,那么这应该不会导致任何问题。请注意上下文打开的时间超过需要的时间。


查看完整回答
反对 回复 2022-11-21
  • 1 回答
  • 0 关注
  • 115 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信