在没有先查询的情况下更新记录?

时间:2010-11-18 19:11:13

标签: c# entity-framework

让我说我查询数据库并加载项目列表。然后我打开详细视图表单中的一个项目,而不是从数据库中重新查询该项目,我从列表中的数据源创建项目的实例。

有没有办法可以更新数据库记录而无需获取单个项目的记录?

以下是我现在如何做的示例:

dataItem itemToUpdate = (from t in dataEntity.items
                                 where t.id == id
                                 select t).FirstOrDefault();

然后在拉动记录后,我更新了项目中的一些值并推回记录:

itemToUpdate.itemstatus = newStatus;
dataEntity.SaveChanges();

我认为有更好的方法可以做到这一点,任何想法?

8 个答案:

答案 0 :(得分:67)

您应该使用Attach()方法。

Attaching and Detaching Objects

答案 1 :(得分:32)

您还可以使用数据存储区的上下文对数据库使用直接SQL。例如:

dataEntity.ExecuteStoreCommand
   ("UPDATE items SET itemstatus = 'some status' WHERE id = 123 ");

出于性能原因,您可能希望传入变量而不是单个硬编码的SQL字符串。这将允许SQL Server缓存查询并使用参数重用。例如:

dataEntity.ExecuteStoreCommand
   ("UPDATE items SET itemstatus = 'some status' WHERE id = {0}", new object[] { 123 });

更新 - 适用于EF 6.0

dataEntity.Database.ExecuteSqlCommand
       ("UPDATE items SET itemstatus = 'some status' WHERE id = {0}", new object[] { 123 });

答案 2 :(得分:7)

如果DataItem有字段,EF将预先验证(如非可空字段),我们必须为此上下文禁用该验证:

DataItem itemToUpdate = new DataItem { Id = id, Itemstatus = newStatus };
dataEntity.Entry(itemToUpdate).Property(x => x.Itemstatus).IsModified = true;
dataEntity.Configuration.ValidateOnSaveEnabled = false;
dataEntity.SaveChanges();
//dataEntity.Configuration.ValidateOnSaveEnabled = true;

否则我们可以尝试满足预验证并仍然只更新单列:

DataItem itemToUpdate = new DataItem
{
    Id = id,
    Itemstatus = newStatus,
    NonNullableColumn = "this value is disregarded - the db original will remain"
};
dataEntity.Entry(itemToUpdate).Property(x => x.Itemstatus).IsModified = true;
dataEntity.SaveChanges();

假设dataEntitySystem.Data.Entity.DbContext

您可以通过将此添加到DbContext

来验证生成的查询
/*dataEntity.*/Database.Log = m => System.Diagnostics.Debug.Write(m);

答案 3 :(得分:7)

代码:

ExampleEntity exampleEntity = dbcontext.ExampleEntities.Attach(new ExampleEntity { Id = 1 });
exampleEntity.ExampleProperty = "abc";
dbcontext.Entry<ExampleEntity>(exampleEntity).Property(ee => ee.ExampleProperty).IsModified = true;
dbcontext.Configuration.ValidateOnSaveEnabled = false;
dbcontext.SaveChanges();

结果TSQL:

exec sp_executesql N'UPDATE [dbo].[ExampleEntities]
SET [ExampleProperty ] = @0
WHERE ([Id] = @1)
',N'@0 nvarchar(32),@1 bigint',@0='abc',@1=1

注意:

&#34; IsModified = true&#34;因为当您创建新的ExampleEntity对象(仅填充了Id属性)时,所有其他属性都具有其默认值(0,null等),因此需要使用line。如果要使用&#34;默认值&#34;更新数据库,实体框架将不会检测到更改,然后数据库将不会更新。

例如:

exampleEntity.ExampleProperty = null;
如果没有行&#34; IsModified = true&#34;

将无法工作,因为属性ExampleProperty在创建空的ExampleEntity对象时已经为空,您需要向EF说这个列必须更新,并且这就是这条线的目的。

答案 4 :(得分:2)

本文作为Microsoft's Getting Started的一部分解释了实体状态以及如何执行此操作:

Add/Attach and Entity States

查看“将现有但已修改的实体附加到上下文”部分

现在我要阅读其余的这些教程了。

答案 5 :(得分:0)

一般来说,如果您使用Entity Framework查询所有项目,并且保存了实体对象,则可以更新实体对象中的各个项目,并在完成后调用SaveChanges()。例如:

var items = dataEntity.Include("items").items;
// For each one you want to change:
items.First(item => item.id == theIdYouWant).itemstatus = newStatus;
// After all changes:
dataEntity.SaveChanges();

检索所需的一个项目不应生成新的查询。

答案 6 :(得分:0)

它在EF Core中的工作方式有些不同:

在EF Core中可能有一种更快的方法,但是以下内容可确保无需执行SELECT即可进行UPDATE(在.NET Framework 4.6.2上经过EF Core 2和JET的测试):

确保您的模型没有IsRequired属性

然后使用以下模板(在VB.NET中):

    Using dbContext = new MyContext()
        Dim bewegung = dbContext.MyTable.Attach(New MyTable())
        bewegung.Entity.myKey = someKey
        bewegung.Entity.myOtherField = "1"

        dbContext.Entry(bewegung.Entity).State = EntityState.Modified
        dbContext.Update(bewegung.Entity)

        Dim BewegungenDescription = (From tp In dbContext.Model.GetEntityTypes() Where tp.ClrType.Name = "MyTable" Select tp).First()
        For Each p In (From prop In BewegungenDescription.GetProperties() Select prop)
            Dim pp = dbContext.Entry(bewegung.Entity).Property(p.Name)
            pp.IsModified = False
        Next
        dbContext.Entry(bewegung.Entity).Property(Function(row) row.myOtherField).IsModified = True
        dbContext.SaveChanges()
    End Using

答案 7 :(得分:0)

我建议使用 Entity Framework Plus

如果您需要使用相同的表达式更新数百或数千个实体,则使用 E​​ntity Framework Core 进行更新可能会非常缓慢。实体在更新之前先加载到上下文中,这对性能非常不利,然后它们一个一个地更新,这使得更新操作更加糟糕。

EF+ 批量更新在单个数据库往返中使用表达式更新多行,无需在上下文中加载实体。

// using Z.EntityFramework.Plus; // Don't forget to include this.

// UPDATE all users inactive for 2 years
var date = DateTime.Now.AddYears(-2);
ctx.Users.Where(x => x.LastLoginDate < date)
         .Update(x => new User() { IsSoftDeleted = 1 });