İlk sorgulamadan bir kayıt güncellensin mi?


104

Veritabanını sorguladığımı ve bir öğe listesi yüklediğimi varsayalım. Daha sonra bir detay görünüm formundaki öğelerden birini açıyorum ve öğeyi veritabanından yeniden sorgulamak yerine, listedeki veri kaynağından öğenin bir örneğini oluşturuyorum.

Tek tek materyalin kaydını getirmeden veritabanı kaydını güncellememin bir yolu var mı?

İşte şimdi nasıl yaptığımın bir örneği:

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

Ardından kaydı aldıktan sonra öğedeki bazı değerleri günceller ve kaydı geri alırım:

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

Bunu yapmanın daha iyi bir yolu olacağını düşünürdüm, herhangi bir fikriniz var mı?


2
İşleri yapmanın çok kötü bir yolu değil. Bu tabloya eşzamanlı erişiminiz var mı?
Henk Holterman

Bunun, EF gibi bir ORM'nin tam olarak hizmet etmek için orada olduğu kullanım olduğunu düşünüyorum. Oluşturmak / değiştirmek / silmek istediğiniz nesneler üzerinde, temeldeki DB uygulamasıyla ilgilenmeden, uygulama bağlamındaki işlemlerin gerçekleştirilmesine izin vermek için?
Pero P.

40
Bence TSQL altyapısı olan geliştiriciler için ORM'leri kabul etmeye ve kucaklamaya çalışıyorlar, bir kaydı yalnızca güncellemek için aramak ve alınan verileri asla kullanmak biraz verimsiz. Bir geliştiricinin temeldeki DB uygulamasıyla ilgilenmesine gerek olmadığı kavramı tam bir güvensizliktir. Bir geliştirici tüm sistem hakkında ne kadar çok şey bilirse, çözüm o kadar iyi olabilir. Seçenekler asla kötü bir şey değildir.
barrypicker

1
ORM yaklaşımı gerçek nesneler için iyidir, ancak veritabanınızda başka şeyler de depoluyorsanız (büyük ikili bloblar gibi), ilk önce orijinal içerikleri yüklemeden bunları güncelleyebilmek çok yararlı olabilir.
BrainSlugs83

Yanıtlar:


68

Sen kullanmalıdır takın () yöntemini.

Nesnelerin Takılması ve Çıkarılması


17
Bir örnek verebilir misiniz?
Bart Calixto

17
context.Products.Attach (ürün); context.Entry (product) .State = EntityState.Modified;
Gabriel

7
@Gabriel Yine de bu tüm özellikleri güncellemeyecek mi? Ya sadece tek bir tane değiştirmek istersem?
David Pfeffer

22
Evet, bu tüm özellikleri güncelleyecektir. Tek bir özelliği güncellemek istiyorsanız, bunu yapabilirsiniz: context.Entry (user) .Property (x => x.Property) .IsModified = true; (buraya bir göz atın stackoverflow.com/a/5567616/57369 )
Gabriel

6
Bu bağlamı eklemek istiyorum.Entry () yalnızca .net 4.1'de mevcuttur, hala 4.0 kullanıyorsanız (benim gibi), alternatif için bunu kontrol edin: stackoverflow.com/questions/7113434/where-is- bağlam giriş esasen: context.ObjectStateManager.ChangeObjectState (yourObject, EntityState.Modified);
dyslexicanaboko

39

Veri deposu bağlamını kullanarak veritabanına karşı doğrudan SQL de kullanabilirsiniz. Misal:

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

Performans nedenleriyle, sabit kodlu tek bir SQL dizesi yerine değişkenleri geçirmek isteyebilirsiniz. Bu, SQL Server'ın sorguyu önbelleğe almasına ve parametrelerle yeniden kullanmasına izin verecektir. Misal:

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

GÜNCELLEME - EF 6.0 için

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

9
neden yorum bırakmadan bu cevabı düşürürsünüz? Bu öneri, orijinal yazarların sorularını doğrudan ele almaktadır.
barrypicker

18
ExecuteStoreCommandGerçekten bunu yapmanın bir EF yol değildir, sadece kullanıyor DbConnectioniçinde bulunan DbContextbir komutu uygulamak için. Kalıcılık bir yana, veritabanından bağımsız değildir (örneğin, OP XML'ye geçerse bu örnek çökebilir).
just.another.programmer

9
@ just.another.programmer - büyük güç, büyük sorumluluk getirir.
barrypicker

13
Sebat agnostik olmak zorunda mı? Depolama sisteminizi her geçen gün değiştirecek değilsiniz.
David

5
@ BrainSlugs83 - EF'i yalnızca OpenQuery'yi destekleyen bağlantı sunucularında kullanmayı deneyin - çok eğlenceli. Bazen işi bitirmek için kesinlikle ham SQL'e ihtiyacınız vardır. Kodu test etmek için her zaman izolasyona çekemezsiniz. Dışarısı mükemmel bir dünya değil.
barrypicker

20

Kod:

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();

Sonuç TSQL:

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

Not:

"IsModified = true" satırı gereklidir, çünkü yeni ExampleEntity nesnesini oluşturduğunuzda (yalnızca Id özelliği doldurulmuşken) diğer tüm özelliklerin varsayılan değerleri (0, null, vb.) Vardır. DB'yi bir "varsayılan değer" ile güncellemek isterseniz, değişiklik varlık çerçevesi tarafından algılanmayacak ve ardından DB güncellenmeyecektir.

Örnek olarak:

exampleEntity.ExampleProperty = null;

"IsModified = true" satırı olmadan çalışmayacaktır, çünkü ExampleProperty özelliği, boş ExampleEntity nesnesini oluşturduğunuzda zaten boştur, EF'e bu sütunun güncellenmesi gerektiğini söylemeniz gerekir ve bu satırın amacı budur.


Bu harika. Bunu daha yeni test ettim ve tam da istediğim buydu. Değişikliklerin EF altyapısından (EntityFramework.Triggers projesini kullanma dahil) geçmesini istiyorum, ancak yalnızca birincil anahtara sahip olarak 1 sütunu değiştirebilmek istedim.
MikeJansen

11

DataItemEF'nin önceden doğrulayacağı alanlar varsa (boş değer atanamayan alanlar gibi), bu bağlam için bu doğrulamayı devre dışı bırakmamız gerekir:

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;

Aksi takdirde, ön doğrulamayı yerine getirmeyi deneyebilir ve yine de yalnızca tek sütunu güncelleyebiliriz:

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();

Varsaymak dataEntitybirSystem.Data.Entity.DbContext

Oluşturulan sorguyu aşağıdakilere ekleyerek doğrulayabilirsiniz DbContext:

/*dataEntity.*/Database.Log = m => System.Diagnostics.Debug.Write(m);


0

EF Core'da biraz farklı çalışır:

Bunu EF Core'da yapmanın daha hızlı bir yolu olabilir, ancak aşağıdakiler bir SELECT yapmak zorunda kalmadan bir GÜNCELLEME sağlar (.NET Framework 4.6.2 üzerinde EF Core 2 ve JET ile test edilmiştir):

Modelinizin IsRequired özelliklerine sahip olmadığından emin olun

Ardından aşağıdaki şablonu kullanın (VB.NET'te):

    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

-1

Genel olarak konuşursak, tüm öğeleri sorgulamak için Entity Framework kullandıysanız ve varlık nesnesini kaydettiyseniz, varlık nesnesindeki tek tek öğeleri güncelleyebilir ve SaveChanges()bitirdiğinizde çağırabilirsiniz . Örneğin:

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();

İstediğiniz bir öğenin alınması yeni bir sorgu oluşturmamalıdır.


İlginç cevap, bunu başka biri doğruladı mı?
Ian

5
Bu, OP'nin problemiyle aynı şeyi yapar: tüm kaydı alın, ardından güncelleyin. İlk () nesnenin serisini kaldırır.
Jerther
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.