在 EF Core 和 .NET 8 中将数据插入多对多的联接表时出现问题

问题描述 投票:0回答:1

我的模型配置如下:

public class Order
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string UserId { get; set; } = null!;
    public DkUser User { get; set; } = null!;
    public int ShippingStatusId { get; set; }
    public ShippingStatus ShippingStatus { get; set; } = null!;
    public DateTime CreatedDate { get; set; }
    public DateTime UpdatedDate { get; set; }
    public string? CreatedBy { get; set; }
    public string? UpdatedBy { get; set; }
    public ICollection<Product> Products { get; set; } = new List<Product>();
    public ICollection<OrderDetail> OrderDetails {get; set;} = [];
}

public class Product
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string Brand { get; set; } = string.Empty;
    public string Model { get; set; } = string.Empty;
    public float Price { get; set; }
    public int View { get; set; }
    public int CategoryId { get; set; }
    public Category? Category { get; set; }
    public int DiscountId { get; set; }
    public Discount Discount { get; set; } = null!;
    public DateTime CreatedDate { get; set; }
    public DateTime UpdatedDate { get; set; }
    public string? CreatedBy { get; set; }
    public string? UpdatedBy { get; set; }
    public ICollection<Order> Orders { get; set; } = new List<Order>();
    public ICollection<OrderDetail> OrderDetails { get; set; } = [];
    public ICollection<ProductPicture> ProductPictures { get; set; } = new List<ProductPicture>();
}

public class OrderDetail
{
    public int ProductId { get; set; }
    public Product Product { get; set; } = new();
    public int OrderId { get; set; }
    public Order Order { get; set; } = new();
    public int Amount { get; set; }
}

class DkdbContext(DbContextOptions<DkdbContext> options) : IdentityDbContext<DkUser>(options)
{
    public DbSet<Computer> Computers { get; set; }
    public DbSet<Product> Products { get; set; }
    public DbSet<Category> Categories { get; set; }
    public DbSet<Order> Orders { get; set; }
    public DbSet<Discount> Discounts { get; set; }
    public DbSet<ShippingStatus> ShippingStatuses { get; set; }
    public DbSet<ProductPicture> ProductPictures { get; set; }
    public DbSet<DkUser> DkUsers { get; set; }
    public DbSet<OrderDetail> OrderDetails { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        builder.Entity<Computer>()
            .HasKey(c => c.Id);
        builder.Entity<Computer>()
            .Property(c => c.Id)
            .HasColumnType("uuid");

        builder.Entity<Category>()
            .HasMany(e => e.Products)
            .WithOne(e => e.Category)
            .HasForeignKey(e => e.CategoryId)
            .IsRequired();

        builder.Entity<Product>()
            .HasOne(e => e.Discount)
            .WithMany(e => e.Products)
            .HasForeignKey(e => e.DiscountId)
            .IsRequired();

        builder.Entity<Product>()
            .Property(e => e.CreatedDate)
            .HasDefaultValueSql("current_timestamp");
        builder.Entity<Product>()
            .Property(e => e.UpdatedDate)
            .HasDefaultValueSql("current_timestamp");
        builder.Entity<Product>()
            .Property(e => e.View)
            .HasDefaultValue(1);

        builder.Entity<Order>()
           .Property(e => e.CreatedDate)
           .HasDefaultValueSql("current_timestamp");
        builder.Entity<Order>()
            .Property(e => e.UpdatedDate)
            .HasDefaultValueSql("current_timestamp");
        builder.Entity<Order>()
            .Property(e => e.ShippingStatusId)
            .HasDefaultValue(1);

        builder.Entity<ProductPicture>()
            .HasOne(e => e.Product)
            .WithMany(e => e.ProductPictures)
            .HasForeignKey(e => e.ProductId)
            .IsRequired();

        // order detail config
        builder.Entity<Product>()
            .HasMany(e => e.Orders)
            .WithMany(e => e.Products)
            .UsingEntity<OrderDetail>();

        builder.Entity<OrderDetail>()
            .Property(e => e.Amount)
            .HasDefaultValue(1);

        // end order detail config

        builder.Entity<ShippingStatus>()
            .HasMany(e => e.Orders)
            .WithOne(e => e.ShippingStatus)
            .HasForeignKey(e => e.ShippingStatusId);

        builder.Entity<DkUser>()
            .HasMany(e => e.Orders)
            .WithOne(e => e.User)
            .HasForeignKey(e => e.UserId);
    }
}

我想创建一个包含 2 种产品和指定相应金额的新订单。以下是我的实现方法:

public class OrderEnpoint
{
    public static void Map(WebApplication app)
    {
        app.MapPost("/order", async (DkdbContext db, OrderDto orderRequest, UserManager<DkUser> userManager) =>
        {
            if (orderRequest == null || string.IsNullOrEmpty(orderRequest.UserId))
                return Results.BadRequest();

            var user = await userManager.FindByIdAsync(orderRequest.UserId);

            var newOrder = new Order
            {
                UserId = orderRequest.UserId,
                CreatedBy = user?.UserName,
                UpdatedBy = user?.UserName,
            };

            await db.Orders.AddAsync(newOrder);
            await db.SaveChangesAsync();

            var _OrderDetails = orderRequest.ProductOrderList
                .Select(e => new OrderDetail
                {
                    OrderId = newOrder.Id,
                    ProductId = e.ProductId,
                    Amount = e.Amount,
                }).ToList();

            await db.OrderDetails.AddRangeAsync(_OrderDetails);
            await db.SaveChangesAsync();

            return Results.Created();
        });
    }
}

这是我的数据传输对象类:

public class OrderDto
{
    public string UserId { get; set; } = string.Empty;
    public List<OrderRequest> ProductOrderList { get; set; } = [];
}

public class OrderRequest
{
    [Required]
    public int ProductId { get; set; }
    [Required]
    public int Amount { get; set; }
}

当我调试此代码时,我可以看到在

Orders
表中创建的订单记录,但在
OrderDetails
中看不到。我使用 postgres 作为数据库。

错误如下所示:

Npgsql.PostgresException(0x80004005):23502:关系“Orders”的“UserId”列中的空值违反了非空约束

详细信息:失败行包含 (15, null, 1, 2024-01-01 14:07:25.091254+00, 2024-01-01 14:07:25.091254+00, null, null)。

异常数据:
严重性:错误
sql状态:23502
MessageText:关系“订单”的“UserId”列中的空值违反了非空约束

详细信息:失败行包含 (15, null, 1, 2024-01-01 14:07:25.091254+00, 2024-01-01 14:07:25.091254+00, null, null)。
模式名称:public
表名:订单
列名称:用户 ID
文件:execMain.c
线路:2003
例程:ExecConstraints

我希望能够创建一个新的

Order
,并分别与关联的
OrderDetail
和金额。我正在寻找解决方案,如果有人可以提供帮助,我很高兴。谢谢你。

postgresql join entity-framework-core asp.net-core-webapi many-to-many
1个回答
0
投票

错误应该出现在下面的代码中,建议设置断点检查用户的状态。

if (orderRequest == null || string.IsNullOrEmpty(orderRequest.UserId))
    return Results.BadRequest();
// need to make sure  the user is not null
var user = await userManager.FindByIdAsync(orderRequest.UserId);

var newOrder = new Order
{
    UserId = orderRequest.UserId,
    CreatedBy = user?.UserName,
    UpdatedBy = user?.UserName,
};

所以修改后的代码如下:

app.MapPost("/order", async (DkdbContext db, OrderDto orderRequest, UserManager<DkUser> userManager) =>
{
    
    if (orderRequest == null || string.IsNullOrEmpty(orderRequest.UserId))
        return Results.BadRequest("Invalid order request or UserId is empty");

    // find user by useid
    var user = await userManager.FindByIdAsync(orderRequest.UserId);
    
    if (user == null)
        return Results.BadRequest("User not found");

    
    var newOrder = new Order
    {
        UserId = orderRequest.UserId,
        CreatedBy = user.UserName,
        UpdatedBy = user.UserName,
    };

    
    await db.Orders.AddAsync(newOrder);
   
    await db.SaveChangesAsync();

    
    var _OrderDetails = orderRequest.ProductOrderList
        .Select(e => new OrderDetail
        {
            OrderId = newOrder.Id,
            ProductId = e.ProductId,
            Amount = e.Amount,
        }).ToList();

    
    await db.OrderDetails.AddRangeAsync(_OrderDetails);
    
    await db.SaveChangesAsync();
    return Results.Created();
});
© www.soinside.com 2019 - 2024. All rights reserved.