.net 实体框架,返回的日期错误

8i9zcol2  于 2023-08-08  发布在  .NET
关注(0)|答案(1)|浏览(110)

我试图使用实体框架为我的API,但在尝试按日期排序对象列表后,发生了一个问题。
我的目标是每天废弃一个网页,将产品保存在数据库中,用我的API访问它。
正如您将在下看到的,数据在SQL DB中是正确的,但使用实体框架,它将返回相同日期的2倍。
我的DB是:

CREATE TABLE [dbo].[ScrappedProducts] (
    [Domain]          VARCHAR (50)    NOT NULL,
    [ProductId]       VARCHAR (50)    NOT NULL,
    [ScrappedDate]    DATE            NOT NULL,
    [ProductUrl]      VARCHAR (256)   NOT NULL,
    [ProductName]     VARCHAR (200)   NOT NULL,
    [ProductBrand]    VARCHAR (200)   NOT NULL,
    [ProductType]     VARCHAR (100)   NOT NULL,
    [ProductAlcool]   DECIMAL (16, 2) NOT NULL,
    [ProductQuantity] INT             NOT NULL,
    [ProductContain]  DECIMAL (16, 2) NOT NULL,
    [ProductPrice]    DECIMAL (16, 2) NOT NULL,
    [ProductImageUrl] VARCHAR (256)   NOT NULL,
    PRIMARY KEY CLUSTERED ([ProductId] ASC, [Domain] ASC, [ScrappedDate] ASC)
);

字符串
我的班级是:

namespace WebScrapperAPI.Components
{
    public class Product
    {
        public string Domain { get; set; }
        public DateTime ScrappedDate {get;set;}
        public string ProductId { get; set; }
        public string ProductUrl { get; set; }
        public string ProductName { get; set; }
        public string ProductBrand { get; set; }
        public string ProductType { get; set; }
        public decimal ProductAlcool { get; set; }
        public int ProductQuantity { get; set; }
        public decimal ProductContain { get; set; }
        public decimal ProductPrice { get; set; }
        public string ProductImageUrl { get; set; }

    }
}


我的DbContext类是:

using Microsoft.EntityFrameworkCore;
using WebScrapperAPI.Components;

namespace WebScrapperAPI.Data
{
    public class ScrapperDBContext : DbContext
    {
        public DbSet<Product> ScrappedProducts { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            string connectionString = "Server=tcp:xxx,xxx;Initial Catalog=xxx;Persist Security Info=False;User ID=xxx;Password=xxx;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;";

            var loggerFactory = LoggerFactory.Create(builder =>
            {
                builder.AddConsole(); // Ajouter la journalisation sur la console
                builder.AddFilter(DbLoggerCategory.Database.Command.Name, LogLevel.Information); // Filtrer les logs SQL uniquement
            });
            optionsBuilder.UseSqlServer(connectionString)
                .UseLoggerFactory(loggerFactory)
                .LogTo(Log, new[] { DbLoggerCategory.Database.Command.Name }, LogLevel.Information);
        }
        private void Log(string t)
        {
            File.WriteAllText("test.txt", t);
        }
    }
}


DB值:

Auchan  0067c78b-7b53-4e2a-b655-d9c071a5ca87    2023-07-18  https://www.auchan.fr/valauria-muscat-vin-doux-naturel-de-rivesaltes-aop-15-5/pr-C1211479   Muscat vin doux naturel de Rivesaltes AOP   VALAURIA    Liquor  15.50   1   75.00   6.65    /static/images/pixel.png

Auchan  0067c78b-7b53-4e2a-b655-d9c071a5ca87    2023-07-19  https://www.auchan.fr/valauria-muscat-vin-doux-naturel-de-rivesaltes-aop-15-5/pr-C1211479   Muscat vin doux naturel de Rivesaltes AOP   VALAURIA    Liquor  15.50   1   75.00   6.65    /static/images/pixel.png


实体框架值:

{
    "domain": "Auchan",
    "scrappedDate": "2023-07-18T00:00:00",
    "productId": "0067c78b-7b53-4e2a-b655-d9c071a5ca87",
    "productUrl": "https://www.auchan.fr/valauria-muscat-vin-doux-naturel-de-rivesaltes-aop-15-5/pr-C1211479",
    "productName": "Muscat vin doux naturel de Rivesaltes AOP",
    "productBrand": "VALAURIA",
    "productType": "Liquor",
    "productAlcool": 15.5,
    "productQuantity": 1,
    "productContain": 75,
    "productPrice": 6.65,
    "productImageUrl": "/static/images/pixel.png"
  },
  {
    "domain": "Auchan",
    "scrappedDate": "2023-07-18T00:00:00",
    "productId": "0067c78b-7b53-4e2a-b655-d9c071a5ca87",
    "productUrl": "https://www.auchan.fr/valauria-muscat-vin-doux-naturel-de-rivesaltes-aop-15-5/pr-C1211479",
    "productName": "Muscat vin doux naturel de Rivesaltes AOP",
    "productBrand": "VALAURIA",
    "productType": "Liquor",
    "productAlcool": 15.5,
    "productQuantity": 1,
    "productContain": 75,
    "productPrice": 6.65,
    "productImageUrl": "/static/images/pixel.png"
  }


编辑:我的查询

public static IEnumerable<Product> GetProducts()
{
    var products = new List<Product>();
    using (var context = new ScrapperDBContext())
    {
        products = context.ScrappedProducts.ToList();
    }
    return products;
}

oxf4rvwz

oxf4rvwz1#

导致问题的原因是应用程序实体Product的主键与表的主键不同。由于在类或DbContex的OnModelBuilding中没有指定键,因此按照约定使用属性ProductID
然而,该表使用PRIMARY KEY CLUSTERED ([ProductId] ASC, [Domain] ASC, [ScrappedDate] ASC),这意味着对于同一个ProductId总是有多行。当EF多次看到相同的PK值时,它会返回相同的缓存对象。
要解决此问题,必须显式指定复合主键:

protected override void OnModelCreating(DbModelBuilder builder)
    {
        builder.Entity<Product>().HasKey(p=> new {
            p.ProductId, 
            p.Domain,
            p.ScrappedDate});
    }

字符串
那不是窃听器主键是内存中实体的标识,因此相同的PK值 * 必须 * 返回相同的对象。否则,应用程序可能会发现自己阅读一个对象并修改另一个对象,即使它们应该是同一个对象。
像NHibernate、Entity Framework这样的ORM,以及基本上所有跟踪对象而不仅仅是Map结果的东西,都使用PK值作为对象的标识。它们的工作是给予人一种处理内存中实体的印象,而不是表和行。通过标识请求相同的对象,应始终返回相同的内存中对象。

相关问题