我试图使用实体框架为我的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;
}
型
1条答案
按热度按时间oxf4rvwz1#
导致问题的原因是应用程序实体
Product
的主键与表的主键不同。由于在类或DbContex的OnModelBuilding
中没有指定键,因此按照约定使用属性ProductID
。然而,该表使用
PRIMARY KEY CLUSTERED ([ProductId] ASC, [Domain] ASC, [ScrappedDate] ASC)
,这意味着对于同一个ProductId
总是有多行。当EF多次看到相同的PK值时,它会返回相同的缓存对象。要解决此问题,必须显式指定复合主键:
字符串
那不是窃听器主键是内存中实体的标识,因此相同的PK值 * 必须 * 返回相同的对象。否则,应用程序可能会发现自己阅读一个对象并修改另一个对象,即使它们应该是同一个对象。
像NHibernate、Entity Framework这样的ORM,以及基本上所有跟踪对象而不仅仅是Map结果的东西,都使用PK值作为对象的标识。它们的工作是给予人一种处理内存中实体的印象,而不是表和行。通过标识请求相同的对象,应始终返回相同的内存中对象。