【问题标题】:dbset.local updating database: a duplicate value cannot be inserted into a unique indexdbset.local 更新数据库:无法将重复值插入唯一索引
【发布时间】:2012-04-27 04:59:18
【问题描述】:

在我的 EF 4.3.1 上调用 entity.savechanges() 时出现错误。我的数据库是一个 sql ce v4 存储,我正在使用 mvvm 模式进行编码。我有一个本地版本的上下文,我将它发送到一个可观察的集合并修改等。这工作正常,当我在数据库中不存在任何行时调用 savechanges() 时,对象仍然很好。当我重新加载应用程序时,对象会按原样填充到我的列表框中,但是如果我添加另一个对象并调用 savechanges(),我会收到一条错误消息,指出无法将重复值插入到唯一索引中。

据我了解,这意味着上下文正在尝试将我的实体保存到数据存储区,但它似乎正在添加我未触及的原始对象以及新对象。我认为这会让他们独自一人,因为他们的状态没有改变。

private void Load()
    {
        entities.Properties.Include("Images").Load();
        PropertyList = new ObservableCollection<Property>();
        PropertyList = entities.Properties.Local;        

        //Sort the list (based on previous session stored in database)
        var sortList = PropertyList.OrderBy(x => x.Sort).ToList();
        PropertyList.Clear();
        sortList.ForEach(PropertyList.Add);

        propertyView = CollectionViewSource.GetDefaultView(PropertyList);
        if (propertyView != null) propertyView.CurrentChanged += new System.EventHandler(propertyView_CurrentChanged);     


        private void NewProperty()
    {
        try
        {
            if (PropertyList != null)
            {                                             
                Property p = new Property()
                    {
                        ID = Guid.NewGuid(),
                        AgentName = "Firstname Lastname",
                        Address = "00 Blank Street",
                        AuctioneerName = "Firstname Lastname",
                        SaleTitle = "Insert a sales title",
                        Price = 0,
                        NextBid = 0,
                        CurrentImage = null,
                        Status = "Auction Pending",
                        QuadVis = false,
                        StatVis = false, //Pause button visibility
                        Sort = PropertyList.Count + 1,                            
                    };

                PropertyList.Add(p);
                SaveProperties();
            }

        private void SaveProperties()
    {
        try
        {               
            foreach (var image in entities.Images.Local.ToList())
            {
                if (image.Property == null)
                    entities.Images.Remove(image);
            }                
        }

        catch (Exception ex)
        {
            System.Windows.MessageBox.Show(ex.Message);
        }

        entities.SaveChanges();
    }

【问题讨论】:

    标签: c# wpf entity-framework mvvm local


    【解决方案1】:

    不评论这里的所有代码,这就是导致您提出的特定问题的原因:

    //Sort the list (based on previous session stored in database) 
    var sortList = PropertyList.OrderBy(x => x.Sort).ToList(); 
    PropertyList.Clear(); 
    sortList.ForEach(PropertyList.Add); 
    

    这段代码:

    • 从已作为未更改实体查询并由上下文跟踪的实体开始。也就是说,已知的实体已经存在于数据库中。
    • 创建这些实体的新排序列表。
    • 对本地集合调用 Clear 会导致每个跟踪的实体被标记为已删除并从集合中移除。
    • 将每个实体重新添加到上下文中,使其现在处于已添加状态,这意味着它是新的,将在调用 SaveChanges 时保存到数据库中,

    您已经有效地告诉 EF,数据库中存在的所有实体实际上都不存在,需要保存。因此它会尝试执行此操作并导致您看到异常。

    要解决此问题,请不要清除 DbContext 本地集合并重新添加实体。相反,您应该使用本地集合在视图中排序以支持视图。

    【讨论】:

    • 为什么我没有看到这个!说需要一双新的眼睛,等我下午回来再试一试。
    【解决方案2】:

    听起来您正在将现有实体添加到上下文(将它们标记为插入)而不是附加它们(将它们标记为现有的、未修改的)。

    我也不确定 new Guid() 是否返回相同的 guid...我总是使用 Guid.NewGuid() http://msdn.microsoft.com/en-us/library/system.guid.newguid.aspx

    【讨论】:

    • Guid 没问题。从保存到数据库的对象中,我可以看到它们都有唯一的 guid。我不完全了解如何使用附加功能,可能是因为我从未想过我需要使用它。我认为 dbset.local 的想法是能够创建上下文的本地版本,以便我可以使用可观察的集合。每当添加/删除某些内容时,本地应与上下文同步。当我调用保存更改时,上下文应该与数据库同步。这个想法正确吗?为什么上下文不应该包含数据库中的现有对象?
    • 我认为大部分情况下您是正确的。当您创建上下文时,它本质上成为您从数据库(附加)通过它加载的实体和您添加到它(添加)的实体的不断增长的内存表示。它还跟踪对这些实体的更改(已修改)并记住您已从上下文中删除的实体(已删除)。调用 SaveChanges() 会导致上下文将其对实体的表示反映回数据库 - (附加 = 忽略,添加 = 插入,修改 = 更新,删除 = 删除)
    • 只是让我觉得这个实现将通过我的应用程序的屋顶拍摄内存。也许我最好在整个应用程序期间只处理本地副本,然后一旦我准备退出并保存,我可以清除整个数据库并使用对象加载它。老实说,我对 Microsoft 印象不深——他们真的没有让 EF 或 WPF 看起来那么吸引人。
    • 在我真正理解它的工作原理之前,我遇到了 Entity Framework 的内存问题。我建议使用单例 - 对 asp 的预请求和对 winforms 的全局请求。我建议的另一件事是在加载您知道不会更改的实体时使用 .AsNoTracking()。
    猜你喜欢
    • 2023-04-03
    • 2012-08-06
    • 1970-01-01
    • 2023-04-02
    • 2013-01-14
    • 1970-01-01
    • 2020-12-10
    • 2013-12-17
    • 1970-01-01
    相关资源
    最近更新 更多