实体框架一个更新属性时,贯穿所有记录(60,000!) [英] Entity Framework runs through all records (60,000!) when updating property for one

查看:171
本文介绍了实体框架一个更新属性时,贯穿所有记录(60,000!)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图设置一个POCO对象的一个​​属性的值,它看起来像实体正在做一个检索数据库中的表中的每个记录,从该POCO对象最初检索到。这里的code:

I am attempting to set the value of a single property for a POCO object, and it's looking like Entity is doing a retrieve of every record in the database table from which the POCO object was originally retrieved. Here's the code:

public void DeleteFile(int fileid)
{
    var context = GetContext(myTrans, false);
    FILE pocofile = (from f in context.FILES.All()
                     where f.File_Id == fileId
                     select f).FirstOrDefault();

    // the following line causes a retrieve of 60,000 records
    pocofile.State_Id = Global.DeletedStateId // global constant

    // additional code that is eventually reached after about 10 minutes
}

我们有一个文件表中有一个 STATE_ID 列映射到一个表。所以,当我试图将STATE_ID属性设置上面,好像设置的第一个文件确定,但由断点它击中了文件 POCO类来看,它看起来像它的做了检索的数据库中每个文件一旦设置了 STATE_ID 从一开始就。

We have a FILES table that has a State_Id column that is mapped to a STATE table. So when I attempt to set the State_Id property above, it seems to set the first file ok, but judging by the breakpoints it's hitting in the FILE poco class, it looks like it's doing a retrieve for every file in the db once it sets the State_Id from the outset.

该FILE.cs类也粘贴如下,以供参考。它基本上是打了很多60,000长循环的getter和setter,如果我对他们中的一个设置断点,在任何给定的时间,并检查FILE_ID在调试器,它的每一次得到了一个新的FILE_ID,这就是我知道它的通过所有这些循环。

The FILE.cs class is also pasted below for reference. It's basically hitting a lot of the getters and setters in a 60,000 long loop, and if I set a breakpoint on one of them at any given time and check the File_Id in the debugger, it's got a new File_Id every time, which is how I know it's looping through all of them.

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated from a template.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;    

namespace FORTRESSPOCO
{
    public partial class FILE
    {
        #region Primitive Properties

        public virtual int File_Id
        {
            get;
            set;
        }

        public virtual string Name
        {
            get;
            set;
        }

        public virtual string Description
        {
            get;
            set;
        }

        public virtual Nullable<System.DateTime> Expiration_Date
        {
            get;
            set;
        }

        public virtual bool Is_Directory
        {
            get;
            set;
        }

        public virtual string Path
        {
            get;
            set;
        }

        public virtual int Data_Asset_Id
        {
            get { return _data_Asset_Id; }
            set
            {
                if (_data_Asset_Id != value)
                {
                    if (Data_Asset != null && Data_Asset.Data_Asset_ID != value)
                    {
                        Data_Asset = null;
                    }
                    _data_Asset_Id = value;
                }
            }
        }
        private int _data_Asset_Id;

        public virtual int State_Id
        {
            get { return _state_Id; }
            set
            {
                if (_state_Id != value)
                {
                    if (STATE != null && STATE.State_Id != value)
                    {
                        STATE = null;
                    }
                    _state_Id = value;
                }
            }
        }
        private int _state_Id;

        #endregion
        #region Navigation Properties

        public virtual Data_Asset Data_Asset
        {
            get { return _data_Asset; }
            set
            {
                if (!ReferenceEquals(_data_Asset, value))
                {
                    var previousValue = _data_Asset;
                    _data_Asset = value;
                    FixupData_Asset(previousValue);
                }
            }
        }
        private Data_Asset _data_Asset;

        public virtual ICollection<File_DateTime_Attribute> File_DateTime_Attribute
        {
            get
            {
                if (_file_DateTime_Attribute == null)
                {
                    var newCollection = new FixupCollection<File_DateTime_Attribute>();
                    newCollection.CollectionChanged += FixupFile_DateTime_Attribute;
                    _file_DateTime_Attribute = newCollection;
                }
                return _file_DateTime_Attribute;
            }
            set
            {
                if (!ReferenceEquals(_file_DateTime_Attribute, value))
                {
                    var previousValue = _file_DateTime_Attribute as FixupCollection<File_DateTime_Attribute>;
                    if (previousValue != null)
                    {
                        previousValue.CollectionChanged -= FixupFile_DateTime_Attribute;
                    }
                    _file_DateTime_Attribute = value;
                    var newValue = value as FixupCollection<File_DateTime_Attribute>;
                    if (newValue != null)
                    {
                        newValue.CollectionChanged += FixupFile_DateTime_Attribute;
                    }
                }
            }
        }
        private ICollection<File_DateTime_Attribute> _file_DateTime_Attribute;

        public virtual ICollection<File_Int_Attribute> File_Int_Attribute
        {
            get
            {
                if (_file_Int_Attribute == null)
                {
                    var newCollection = new FixupCollection<File_Int_Attribute>();
                    newCollection.CollectionChanged += FixupFile_Int_Attribute;
                    _file_Int_Attribute = newCollection;
                }
                return _file_Int_Attribute;
            }
            set
            {
                if (!ReferenceEquals(_file_Int_Attribute, value))
                {
                    var previousValue = _file_Int_Attribute as FixupCollection<File_Int_Attribute>;
                    if (previousValue != null)
                    {
                        previousValue.CollectionChanged -= FixupFile_Int_Attribute;
                    }
                    _file_Int_Attribute = value;
                    var newValue = value as FixupCollection<File_Int_Attribute>;
                    if (newValue != null)
                    {
                        newValue.CollectionChanged += FixupFile_Int_Attribute;
                    }
                }
            }
        }
        private ICollection<File_Int_Attribute> _file_Int_Attribute;

        public virtual ICollection<File_String_Attribute> File_String_Attribute
        {
            get
            {
                if (_file_String_Attribute == null)
                {
                    var newCollection = new FixupCollection<File_String_Attribute>();
                    newCollection.CollectionChanged += FixupFile_String_Attribute;
                    _file_String_Attribute = newCollection;
                }
                return _file_String_Attribute;
            }
            set
            {
                if (!ReferenceEquals(_file_String_Attribute, value))
                {
                    var previousValue = _file_String_Attribute as FixupCollection<File_String_Attribute>;
                    if (previousValue != null)
                    {
                        previousValue.CollectionChanged -= FixupFile_String_Attribute;
                    }
                    _file_String_Attribute = value;
                    var newValue = value as FixupCollection<File_String_Attribute>;
                    if (newValue != null)
                    {
                        newValue.CollectionChanged += FixupFile_String_Attribute;
                    }
                }
            }
        }
        private ICollection<File_String_Attribute> _file_String_Attribute;

        public virtual STATE STATE
        {
            get { return _sTATE; }
            set
            {
                if (!ReferenceEquals(_sTATE, value))
                {
                    var previousValue = _sTATE;
                    _sTATE = value;
                    FixupSTATE(previousValue);
                }
            }
        }
        private STATE _sTATE;

        #endregion
        #region Association Fixup

        private void FixupData_Asset(Data_Asset previousValue)
        {
            if (previousValue != null && previousValue.FILES.Contains(this))
            {
                previousValue.FILES.Remove(this);
            }

            if (Data_Asset != null)
            {
                if (!Data_Asset.FILES.Contains(this))
                {
                    Data_Asset.FILES.Add(this);
                }
                if (Data_Asset_Id != Data_Asset.Data_Asset_ID)
                {
                    Data_Asset_Id = Data_Asset.Data_Asset_ID;
                }
            }
        }

        private void FixupSTATE(STATE previousValue)
        {
            if (previousValue != null && previousValue.FILES.Contains(this))
            {
                previousValue.FILES.Remove(this);
            }

            if (STATE != null)
            {
                if (!STATE.FILES.Contains(this))
                {
                    STATE.FILES.Add(this);
                }
                if (State_Id != STATE.State_Id)
                {
                    State_Id = STATE.State_Id;
                }
            }
        }

        private void FixupFile_DateTime_Attribute(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems != null)
            {
                foreach (File_DateTime_Attribute item in e.NewItems)
                {
                    item.FILE = this;
                }
            }

            if (e.OldItems != null)
            {
                foreach (File_DateTime_Attribute item in e.OldItems)
                {
                    if (ReferenceEquals(item.FILE, this))
                    {
                        item.FILE = null;
                    }
                }
            }
        }

        private void FixupFile_Int_Attribute(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems != null)
            {
                foreach (File_Int_Attribute item in e.NewItems)
                {
                    item.FILE = this;
                }
            }

            if (e.OldItems != null)
            {
                foreach (File_Int_Attribute item in e.OldItems)
                {
                    if (ReferenceEquals(item.FILE, this))
                    {
                        item.FILE = null;
                    }
                }
            }
        }

        private void FixupFile_String_Attribute(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems != null)
            {
                foreach (File_String_Attribute item in e.NewItems)
                {
                    item.FILE = this;
                }
            }

            if (e.OldItems != null)
            {
                foreach (File_String_Attribute item in e.OldItems)
                {
                    if (ReferenceEquals(item.FILE, this))
                    {
                        item.FILE = null;
                    }
                }
            }
        }

        #endregion
    }
}

是否有此行为的任何合乎逻辑的理由吗?谢谢你。

Is there any logical reason for this behavior? Thanks.

推荐答案

是的,有这种行为的一个合乎逻辑的理由。但是,这不是你在我的意见,但在EF 4.0 POCO T4模板的错错。问题是,这些自动生成的修正... 方法与延迟加载一起的组合。

Yes, there is a logical reason for this behaviour. But it's not your fault in my opinion but the EF 4.0 POCO T4 template's fault. The problem is the combination of those autogenerated Fixup... methods together with lazy loading.

会出现以下情况:

  • 您设置FK属性:

  • You set the FK property:

pocofile.State_Id = Global.DeletedStateId;

  • 它调用 STATE_ID 二传手:

  • It calls the State_Id setter:

    if (_state_Id != value)
    {
        if (STATE != null && STATE.State_Id != value)
        {
            STATE = null;
        }
        _state_Id = value;
    }
    

  • 第一个如果条件,除非你设置相同的 FK 值装入的实体已经有(没有变化FK的)。第二个如果的条件将,因为延迟加载会加载状态从EX pression数据库状态!= NULL 键,因为状态数据库不能,因为你们的关系是不可为空( STATE_ID INT )。 STATE.State_Id 不等于如果 _state_Id 是不等于,这将违反在DB的FK约束。因此, STATE = NULL 执行。换句话说导航setter方法​​状态被称为:

  • The first if condition is true unless you set the same FK value that the loaded entity has already (no change of FK). The second if condition will be true because lazy loading will load the STATE from the database in the expression STATE != null and because the STATE in the database cannot be null since your relationship is not nullable (State_Id is an int). STATE.State_Id cannot be equal to value if _state_Id is not equal to value, it would violate the FK constraint in the DB. So, STATE = null is executed. In other words the setter of the navigation property STATE is called:

    if (!ReferenceEquals(_sTATE, value))
    {
        var previousValue = _sTATE;
        _sTATE = value;
        FixupSTATE(previousValue);
    }
    

  • 如果条件又因为 _STATE 不是(它只是已被加载从DB前)和。因此, FixupSTATE 将会被调用,参数 previousValue 不是

  • The if condition is true again because _STATE is not null (it just has been loaded from the DB before) and value is null. So, FixupSTATE will be called with a parameter previousValue that is not null:

    if (previousValue != null && previousValue.FILES.Contains(this))
        //...
    

  • 现在,如果延迟加载启用(这是默认设置)访问 previousValue.FILES 收集将导致延迟加载来踢,发出数据库查询负载整个 previousValue.FILES 从数据库集合 - 这似乎包含60000实体的情况下

  • Now, if lazy loading is enabled (and it is by default) accessing the previousValue.FILES collection will cause lazy loading to kick in and issue a database query the loads the whole previousValue.FILES collection from the database - which seem to contain 60000 entities in your case.

    对于这个问题的解决办法是禁用延迟加载:

    The solution for this problem is to disable lazy loading:

    var context = GetContext(myTrans, false);
    context.ContextOptions.LazyLoadingEnabled = false;
    
    //...
    

    或者修改T4模板,以便它不会再创建修正code(可能很难得到它的权利)。或者,也许已经有了关于EF 4.0在那里,你可以使用修改后的T4模板。或者,升级到EF> = 4.1和的DbContext ,因为POCO模板的DbContext 没有这种额外的code。生成的POCO类是非常简单的话。

    Or, modify the T4 template so that it doesn't create the Fixup code anymore (might be difficult to get it right). Or, maybe there already is a modified T4 template for EF 4.0 out there you can use. Or, upgrade to EF >= 4.1 and DbContext because the POCO template for DbContext doesn't have this additional code. The generated POCO classes are much simpler then.

    这篇关于实体框架一个更新属性时,贯穿所有记录(60,000!)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆