我正在尝试为我的 API 使用 Entity Framework ,但在尝试按日期对对象列表进行排序后,出现了问题。
我的目标是每天废弃一个网页,将产品保存在数据库中,并使用我的 API 访问它。
正如您将在下面看到的,SQL DB 中的数据是正确的,但是使用 Entity Framework ,它将返回同一日期的 2 倍。
我的数据库是:
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)
);
我的类(class)是:
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);
}
}
}
数据库值:
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
Entity Framework 值:
{
"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;
}
最佳答案
导致该问题的原因是应用程序实体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 值必须返回相同的对象。否则,应用程序可能会发现自己正在读取一个对象并修改另一个对象,即使它们应该是同一个对象。
ORM(例如 NHibernate、Entity Framework 以及基本上所有跟踪对象而不仅仅是映射结果的东西)都使用 PK 值作为对象的标识。他们的工作是给人一种使用内存中实体的印象,而不是表和行。通过身份请求相同的对象,应该始终返回相同的内存对象。
关于c# - Entity Framework ,返回日期错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76722503/