Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 断开EF核更新的有效方法_C#_Database_Postgresql_Entity Framework_Entity Framework Core - Fatal编程技术网

C# 断开EF核更新的有效方法

C# 断开EF核更新的有效方法,c#,database,postgresql,entity-framework,entity-framework-core,C#,Database,Postgresql,Entity Framework,Entity Framework Core,我有一个ASP.NET核心web服务。这与使用EntityFrameworkCore1.1的Postgres数据库进行对话。当服务需要更新数据库记录以响应客户端请求时,有两种方法 方法1 从数据库检索要更新的记录 将从客户端接收的值映射到数据库实体 在数据库上下文上调用SaveChanges 方法2 对从客户端接收的记录传入的数据库上下文调用Update。(如果需要,从DTO映射到数据库实体) 在数据库上下文上调用SaveChanges 这两种方法的表现非常不同 方法1 职业选手。仅更新已从数据

我有一个ASP.NET核心web服务。这与使用EntityFrameworkCore1.1的Postgres数据库进行对话。当服务需要更新数据库记录以响应客户端请求时,有两种方法

方法1

  • 从数据库检索要更新的记录

  • 将从客户端接收的值映射到数据库实体

  • 在数据库上下文上调用SaveChanges

  • 方法2

  • 对从客户端接收的记录传入的数据库上下文调用Update。(如果需要,从DTO映射到数据库实体)

  • 在数据库上下文上调用SaveChanges

  • 这两种方法的表现非常不同

    方法1

    职业选手。仅更新已从数据库中的值更改的值

    骗局。需要执行两次数据库往返。(检索实体,然后更新)

    方法2

    职业选手。只需执行一次数据库往返

    骗局。更新传入的整个对象图,即使实体中只有一个值已更改

    实体框架核心文档中关于使用断开连接的实体的页面尚未编写

    我们没有一个完整的生产系统,没有足够的数据来有效地测试这一点,在我们试图解决应用程序中风险最大的部分的开发阶段,基于经验的优化并不是我们现在投资的足够优先事项

    考虑到Web服务器和数据库服务器将位于同一个数据中心内,我所寻找的是一种有点知情的“10人入门”方法,如果需要,我们可能会在以后花时间进行优化

    我的问题是这两种方法的表现完全不同,但我没有发现任何信息可以帮助我在它们之间做出选择,如果没有一个具有代表性吞吐量的实际大小的测试系统,我怀疑我所能做的任何快速简单的本地测试的解释对于生产规模系统的带宽和占用率来说都是毫无意义的

    我非常欢迎您提供任何信息或指导。

    您可能会发现这些信息非常有用。ASP.NET Core的示例使用EF Core

    就个人而言,我倾向于使用第一种方法,即加载实体、更新实体和调用SaveChanges,原因有二:

  • 方法2意味着实体中的所有数据都将被公开,隐藏的值可能会被更改。这是一种安全风险
  • 方法2通常更快,但如果实体中有大量数据,则可能会更慢,尤其是在web连接速度较慢的情况下
  • 大多数应用程序都有更多的读写操作,因此我倾向于关注查询,除非测试显示更新/创建/删除速度较慢。

    您可能会发现有用的方法。ASP.NET Core的示例使用EF Core

    就个人而言,我倾向于使用第一种方法,即加载实体、更新实体和调用SaveChanges,原因有二:

  • 方法2意味着实体中的所有数据都将被公开,隐藏的值可能会被更改。这是一种安全风险
  • 方法2通常更快,但如果实体中有大量数据,则可能会更慢,尤其是在web连接速度较慢的情况下

  • 大多数应用程序都有更多的读写操作,因此我倾向于关注查询,除非测试显示更新/创建/删除速度较慢。

    我的回答是方法2

    提要 我只想修改实体的少数列,以及添加\修改嵌套子实体

    • 这里,我正在更新
      场景
      实体,并且只修改
      场景日期
    • 在其子实体中,即导航属性
      tempsecenario
      ,我正在添加一条新记录
    • 在嵌套的子实体中,
      Scenariostation
      ,我正在添加和修改记录
    但是,对于断开连接的EF核心更新,这里的问题是,如果使用此
    DbContext.Entry(entity).EntityState=EntityState.IsModified
    ,所有列都将更新。 因此,某些列将更新为其默认值,即null或默认数据类型值

    此外,
    ScenarioStation
    的一些记录根本不会更新,因为实体状态将保持不变

    因此,为了只更新从客户端发送的列,需要以某种方式告诉EF核心

    使用ChangeTracker.TrackGraph 最近我发现了这个
    DbConetxt.ChangeTracker.TrackGraph
    方法,它可以用来标记实体的
    添加的
    未更改的
    状态

    不同之处在于,使用
    TrackGraph
    ,您可以添加自定义逻辑,因为它可以迭代导航实体的导航属性

    使用轨迹图的自定义逻辑
    public virtual void UpdateThroughGraph(T实体,字典列stobeupdated)
    {
    if(实体==null)
    抛出新的ArgumentNullException(“实体”);
    _context.ChangeTracker.TrackGraph(实体,e=>
    {
    字符串navigationPropertyName=e.Entry.Entity.GetType().Name;
    if(例如Entry.IsKeySet)
    {
    e、 Entry.State=EntityState.Unchanged;
    e、 Entry.Property(“Modifieddate”).CurrentValue=DateTime.Now;
    if(columnsToBeUpdated.ContainsKey(navigationPropertyName))
    {
    foreach(e.Entry.Properties中的var属性)
    {
    如果(ColumnStobeUpdate[e.Entry.Entity.GetType().Name]。包含(property.Metadata.Name))
    {
    property.IsModified=true;
    }
    }
    }
    }
    其他的
    
    public partial class Scenario
    {
        public Scenario()
        {
            InverseTempscenario = new HashSet<Scenario>();
            Scenariostation = new HashSet<Scenariostation>();
        }
        public int Scenarioid { get; set; }
        public string Scenarioname { get; set; }
        public DateTime? Scenariodate { get; set; }
        public int Streetlayerid { get; set; }
        public string Scenarionotes { get; set; }
        public int? Modifiedbyuserid { get; set; }
        public DateTime? Modifieddate { get; set; }
        public int? Tempscenarioid { get; set; }
    
        
        public virtual Scenario Tempscenario { get; set; }
        public virtual ICollection<Scenario> InverseTempscenario { get; set; }
        public virtual ICollection<Scenariostation> Scenariostation { get; set; }
    }
    
    
    public partial class Scenariostation
    {
        public Scenariostation()
        {
            Scenariounit = new HashSet<Scenariounit>();
        }
    
        public int Scenariostationid { get; set; }
        public int Scenarioid { get; set; }
        public int Stationid { get; set; }
        public bool? Isapplicable { get; set; }
        public int? Createdbyuserid { get; set; }
        public int? Modifiedbyuserid { get; set; }
        public DateTime? Modifieddate { get; set; }
        
        public virtual Scenario Scenario { get; set; }
        public virtual Station Station { get; set; }
    }
    
    public partial class Station
    {
        public Station()
        {
            Scenariostation = new HashSet<Scenariostation>();
        }
    
        public int Stationid { get; set; }
        public string Stationname { get; set; }
        public string Address { get; set; }
        public NpgsqlPoint? Stationlocation { get; set; }
        public int? Modifiedbyuserid { get; set; }
        public DateTime? Modifieddate { get; set; }
    
        public virtual ICollection<Scenariostation> Scenariostation { get; set; }
    }
    
    public virtual void Update(T entity)
    {
        if (entity == null)
            throw new ArgumentNullException("entity");
    
        var returnEntity = _dbSet.Attach(entity);
        _context.Entry(entity).State = EntityState.Modified;
    }
    
    
    public virtual void UpdateThroughGraph(T entity, Dictionary<string, List<string>> columnsToBeUpdated)
    {
        if (entity == null)
            throw new ArgumentNullException("entity");
    
        _context.ChangeTracker.TrackGraph(entity, e =>
        {
            string navigationPropertyName = e.Entry.Entity.GetType().Name;
    
            if (e.Entry.IsKeySet)
            {
                e.Entry.State = EntityState.Unchanged;
                e.Entry.Property("Modifieddate").CurrentValue = DateTime.Now;
    
                if (columnsToBeUpdated.ContainsKey(navigationPropertyName))
                {
                    foreach (var property in e.Entry.Properties)
                    {
                        if (columnsToBeUpdated[e.Entry.Entity.GetType().Name].Contains(property.Metadata.Name))
                        {
                            property.IsModified = true;
                        }
                    }
                }
            }
            else
            {
                e.Entry.State = EntityState.Added;
            }
    
        });
    
    }