C# 断开EF核更新的有效方法
我有一个ASP.NET核心web服务。这与使用EntityFrameworkCore1.1的Postgres数据库进行对话。当服务需要更新数据库记录以响应客户端请求时,有两种方法 方法1C# 断开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 职业选手。仅更新已从数据
大多数应用程序都有更多的读写操作,因此我倾向于关注查询,除非测试显示更新/创建/删除速度较慢。我的回答是方法2 提要 我只想修改实体的少数列,以及添加\修改嵌套子实体
- 这里,我正在更新
实体,并且只修改场景
场景日期
- 在其子实体中,即导航属性
,我正在添加一条新记录tempsecenario
- 在嵌套的子实体中,
,我正在添加和修改记录Scenariostation
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;
}
});
}