实体框架数据库首先了解数据库中设置的唯一键吗?

时间:2015-12-31 10:52:57

标签: c# entity-framework

EF6。

我首先使用EF6数据库。

我的数据库表在6列上有唯一键。一切都在项目中运作良好。然后我意识到唯一键是不正确的,我不需要它,所以我从数据库中删除它。

我有Product,其中包含ICollection<ProdPrice> ProdPrices

现在,当我使用Product product = db.Products.Find(id);时,我得到了一个产品,但ProdPrices集合只包含6个应该包含12个项目。(前6个项目在列表中)。

如果我从数据库中删除第一项并再次运行代码,则会返回6项 - 项目2 - 7.

如果我更改了列中 列中的某个值,那么该项中的项将会出现在

中。

所以我认为EF在某种程度上记住了唯一键,只返回了与唯一键不冲突的第一项。

我试图在edml文件中“从数据库更新模型” - 没有解决问题。所以我从edml中删除了ProdPrice表,“从数据库更新模型” - 没有用。

所以我的问题是 - 我是否正确说EF正在记住已删除的唯一密钥?如果是,我如何让它忘记呢?如果我不对,那你可以解释实际发生的事情吗?

编辑:通过调用数据库生成的SQL - 标准select语句,它在SSMS中运行时返回所有12条记录(为便于阅读而删除列):

SELECT 
[Extent1].[ProdPriceID] AS [ProdPriceID], 
[Extent1].[ProdID] AS [ProdID],
[Extent1].[PermanentlyDelete] AS [PermanentlyDelete], 
[Extent1].[DateCreated] AS [DateCreated]
FROM [dbo].[ProdPrice] AS [Extent1]
WHERE [Extent1].[ProdID] = 67577

以下是结果,因此您可以看到我获得了12条记录。

SSMS Results

代码结果:

Code Result

所以我决定只要求产品的价格 - 我得到12个结果,这真让我感到困惑:

Prices only

编辑: 我以为我已经解决了...... 为了解决(并进一步测试),我决定在db中重新创建ProdPrice表 - 我这样做是通过使用MSSSMS生成脚本并包含数据,因此我有一个表的精确副本,称之为ProdPrice2。

我的系统中有ProdPrice和ProdPrice2实体(这确认我仍然连接到正确的数据库)。 ProdPrice仍然只返回与原始唯一索引不冲突的记录。 ProdPrice2 - 返回所有记录!

哎呀,以为就是这样 - 然后我从我的系统中删除了ProdPrice,离开了ProdPrice2 - 我运行了系统,ProdPrice2现在只有6条记录,而不是之前的12条记录!

我添加了ProdPrice.ProdPrice2仍然有6条记录,ProdPrice现在已经有了所有预期记录。

我被殴打!!!!这真的阻止了我的发展!在解决之前我不能继续!

3 个答案:

答案 0 :(得分:3)

经过几天的摔跤和@AlbertoMonteiro的一些出色的帮助和建议,我无法得到我期望的行为。

在继续尝试各种各样的事情和调试之后,我最终点击了一些我忘记在那里的代码......!

原来问题的答案

  

Entity Framework Database是否首先了解数据库中设置的唯一键?

是,没有实体框架数据库首先了解数据库中设置的唯一密钥。

但是,

EF会在创建实体列表时使用任何重写的Equals()函数。在我的代码中,我已经覆盖了Equals函数来模仿数据库中的唯一键,这意味着当我添加到我可以匹配的价格列表时,重复&#34;重复&#34;并将它们合并在一起。这段代码导致我的价格列表没有完全填充,因为我改变了我希望系统工作的方式。

答案是我是个白痴,我应该记住我写过的代码。我会在这里留下这个问题,因为这可能会阻止某人在将来失去几天的发展。

答案 1 :(得分:1)

此问题中的实体框架,不用担心您删除的唯一密钥,此唯一密钥也不会在您选择内容时过滤数据,唯一密钥可防止您无法添加具有相同唯一密钥的另一行

同样,这个独特的密钥并不是一个麻烦,EF并不关心它。

但是你可以调试从EF生成的SQL并检查为什么你只从属性 ProdPrices 获得6个项目。

我们可以使用上下文中的 Database.Log 属性来分析生成的SQL。

你说你有这个代码行Product product = db.Products.Find(id);

让我们稍微修改它来分析sql。

//Add breakpoint in this line
Product product = db.Products.Find(id); 
db.Database.Log = sql => System.Diagnostics.Debug.WriteLine(sql);
var prodPrices = product.ProdPrices.ToList();
//Next line
  • 在第一行(找到产品)中添加一个breackpoint
  • F10 (跳过)3次
  • 创建 prodPrices
  • 后,断点必须现在位于下一行代码中
  • 打开“输出”窗口
  • 从ProdPrice生成的SQL应该在那里

分析SQL查询,在SSMS中执行并检查结果。

我在我的机器上尝试了这个,但它运行正常:

public class Program
{
    public static void Main(string[] args)
    {
        using (var ctx = new MyClass())
        {
            if (!ctx.Products.Any())
            {
                var product = new Product
                {
                    ProdPrices = new List<ProdPrice>
                    {
                        new ProdPrice {PermanentlyDelete = true, DateCreated = new DateTime(2015,12,29,18,28,27)},
                        new ProdPrice {PermanentlyDelete = true, DateCreated = new DateTime(2015,12,29,18,28,28)},
                        new ProdPrice {PermanentlyDelete = true, DateCreated = new DateTime(2015,12,29,18,28,28)},
                        new ProdPrice {PermanentlyDelete = true, DateCreated = new DateTime(2015,12,29,18,28,29)},
                        new ProdPrice {PermanentlyDelete = true, DateCreated = new DateTime(2015,12,29,18,28,29)},
                        new ProdPrice {PermanentlyDelete = true, DateCreated = new DateTime(2015,12,30,19,08,38)},
                        new ProdPrice {PermanentlyDelete = false, DateCreated = new DateTime(2015,12,31,10,18,06)},
                        new ProdPrice {PermanentlyDelete = false, DateCreated = new DateTime(2015,12,31,10,18,06)},
                        new ProdPrice {PermanentlyDelete = false, DateCreated = new DateTime(2015,12,31,10,18,07)},
                        new ProdPrice {PermanentlyDelete = false, DateCreated = new DateTime(2015,12,31,10,18,07)},
                        new ProdPrice {PermanentlyDelete = false, DateCreated = new DateTime(2015,12,31,10,18,08)},
                        new ProdPrice {PermanentlyDelete = false, DateCreated = new DateTime(2015,12,31,10,18,08)},
                    }
                };

                ctx.Products.Add(product);
                ctx.SaveChanges();
                Console.WriteLine("Saved");
            }
        }
        using (var ctx = new MyClass())
        {
            var product = ctx.Products.Find(1);
            var count = product.ProdPrices.Count;
            Console.WriteLine(count);
        }
    }
}

public class MyClass : DbContext
{
    public DbSet<Product> Products { get; set; }
    public DbSet<ProdPrice> ProdPrices { get; set; }
}

public class Product
{
    [Key]
    public long ProdID { get; set; }
    public virtual ICollection<ProdPrice> ProdPrices { get; set; }
}

public class ProdPrice
{
    public long ProdPriceID { get; set; }
    public bool PermanentlyDelete { get; set; }
    public DateTime DateCreated { get; set; }
}

答案 2 :(得分:0)

您似乎只创建了一次dbcontext,这也是静态的。

当您对db进行fetch / write调用时,创建一个新的上下文,应该这样做。

再次,

创建一个包含DbContext的基类,并在每次需要与db通信时继承该类。

像这样的东西

public class TheDBEntities
{
    private TheDBEntities _context = new TheDBEntities();

    protected TheDBEntities Context { get; private set; }

    protected TheDataContext()
    {

        Context = _context;
    }


    protected void SaveChanges()
    {
        Context.SaveChanges();
    }

    protected void SaveChangesAsync()
    {
        Context.SaveChangesAsync();
    }


}


public class DBBusinessLayer: TheDBEntities
{
    public DBBusinessLayer() { }

    public void GetData(int id)
    {
        // use it here Context.<yourentities>
    }
}