बस इसके अलावा (चिह्नित उत्तर में) और (ईएफ कोर में) के बीच एक महत्वपूर्ण अंतर है :context.Entry(entity).State = EntityState.Unchanged
context.Attach(entity)
मैंने इसे स्वयं समझने के लिए कुछ परीक्षण किए (इसलिए इसमें कुछ सामान्य संदर्भ परीक्षण भी शामिल हैं), इसलिए यह मेरा परीक्षण-परिदृश्य है:
- मैंने EF Core 3.1.3 का उपयोग किया
- मैंनें इस्तेमाल किया
QueryTrackingBehavior.NoTracking
- मैंने मैपिंग के लिए केवल विशेषताओं का उपयोग किया है (नीचे देखें)
- मैंने ऑर्डर प्राप्त करने और ऑर्डर को अपडेट करने के लिए विभिन्न संदर्भों का उपयोग किया
- मैंने हर टेस्ट के लिए पूरी डीबी मिटा दी
ये मॉडल हैं:
public class Order
{
public int Id { get; set; }
public string Comment { get; set; }
public string ShippingAddress { get; set; }
public DateTime? OrderDate { get; set; }
public List<OrderPos> OrderPositions { get; set; }
[ForeignKey("OrderedByUserId")]
public User OrderedByUser { get; set; }
public int? OrderedByUserId { get; set; }
}
public class OrderPos
{
public int Id { get; set; }
public string ArticleNo { get; set; }
public int Quantity { get; set; }
[ForeignKey("OrderId")]
public Order Order { get; set; }
public int? OrderId { get; set; }
}
public class User
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
यह डेटाबेस में (मूल) परीक्षण डेटा है:
आदेश प्राप्त करने के लिए:
order = db.Orders.Include(o => o.OrderPositions).Include(o => o.OrderedByUser).FirstOrDefault();
अब परीक्षण:
EntityState के साथ सरल अद्यतन :
db.Entry(order).State = EntityState.Unchanged;
order.ShippingAddress = "Germany"; // will be UPDATED
order.OrderedByUser.FirstName = "William (CHANGED)"; // will be IGNORED
order.OrderPositions[0].ArticleNo = "K-1234 (CHANGED)"; // will be IGNORED
order.OrderPositions.Add(new OrderPos { ArticleNo = "T-5555 (NEW)", Quantity = 5 }); // will be INSERTED
db.SaveChanges();
// Will generate SQL in 2 Calls:
// INSERT INTO [OrderPositions] ([ArticleNo], [OrderId], [Quantity]) VALUES ('T-5555', 1, 5)
// UPDATE [Orders] SET [ShippingAddress] = 'Germany' WHERE [Id] = 1
अटैच के साथ सरल अद्यतन :
db.Attach(order);
order.ShippingAddress = "Germany"; // will be UPDATED
order.OrderedByUser.FirstName = "William (CHANGED)"; // will be UPDATED
order.OrderPositions[0].ArticleNo = "K-1234 (CHANGED)"; // will be UPDATED
order.OrderPositions.Add(new OrderPos { ArticleNo = "T-5555 (NEW)", Quantity = 5 }); // will be INSERTED
db.SaveChanges();
// Will generate SQL in 1 Call:
// UPDATE [OrderPositions] SET [ArticleNo] = 'K-1234' WHERE [Id] = 1
// INSERT INTO [OrderPositions] ([ArticleNo], [OrderId], [Quantity]) VALUES ('T-5555 (NEW)', 1, 5)
// UPDATE [Orders] SET [ShippingAddress] = 'Germany' WHERE [Id] = 1
// UPDATE [Users] SET [FirstName] = 'William (CHANGED)' WHERE [Id] = 1
EntityState के साथ चाइल्ड- आईडीएस बदलने के साथ अपडेट करें :
db.Entry(order).State = EntityState.Unchanged;
order.ShippingAddress = "Germany"; // will be UPDATED
order.OrderedByUser.Id = 3; // will be IGNORED
order.OrderedByUser.FirstName = "William (CHANGED)"; // will be IGNORED
order.OrderPositions[0].Id = 3; // will be IGNORED
order.OrderPositions[0].ArticleNo = "K-1234 (CHANGED)"; // will be IGNORED
order.OrderPositions.Add(new OrderPos { ArticleNo = "T-5555 (NEW)", Quantity = 5 }); // will be INSERTED
db.SaveChanges();
// Will generate SQL in 2 Calls:
// INSERT INTO [OrderPositions] ([ArticleNo], [OrderId], [Quantity]) VALUES ('T-5555', 1, 5)
// UPDATE [Orders] SET [ShippingAddress] = 'Germany' WHERE [Id] = 1
अटैच के साथ बदलते चाइल्ड-आईड्स के साथ अपडेट :
db.Attach(order);
order.ShippingAddress = "Germany"; // would be UPDATED
order.OrderedByUser.Id = 3; // will throw EXCEPTION
order.OrderedByUser.FirstName = "William (CHANGED)"; // would be UPDATED
order.OrderPositions[0].Id = 3; // will throw EXCEPTION
order.OrderPositions[0].ArticleNo = "K-1234 (CHANGED)"; // would be UPDATED
order.OrderPositions.Add(new OrderPos { ArticleNo = "T-5555 (NEW)", Quantity = 5 }); // would be INSERTED
db.SaveChanges();
// Throws Exception: The property 'Id' on entity type 'User' is part of a key and so cannot be modified or marked as modified. To change the principal of an existing entity with an identifying foreign key first delete the dependent and invoke 'SaveChanges' then associate the dependent with the new principal.)
नोट: यह अपवाद को फेंकता है, भले ही ईद को बदल दिया गया हो या मूल मूल्य पर सेट कर दिया गया हो, ऐसा लगता है जैसे आईडी की स्थिति "परिवर्तित" पर सेट है और इसकी अनुमति नहीं है (क्योंकि यह प्राथमिक कुंजी है)
नए के रूप में बदलते चाइल्ड-आईडीएस के साथ अपडेट करें (एंटिटीस्टेट और अटैच के बीच कोई अंतर नहीं):
db.Attach(order); // or db.Entry(order).State = EntityState.Unchanged;
order.OrderedByUser = new User();
order.OrderedByUser.Id = 3; // // Reference will be UPDATED
order.OrderedByUser.FirstName = "William (CHANGED)"; // will be UPDATED (on User 3)
db.SaveChanges();
// Will generate SQL in 2 Calls:
// UPDATE [Orders] SET [OrderedByUserId] = 3, [ShippingAddress] = 'Germany' WHERE [Id] = 1
// UPDATE [Users] SET [FirstName] = 'William (CHANGED)' WHERE [Id] = 3
नोट: नई (ऊपर) के बिना EntityState के साथ अद्यतन करने के लिए अंतर देखें। नए उपयोगकर्ता उदाहरण के कारण, इस बार नाम अपडेट किया जाएगा।
EntityState के साथ संदर्भ-आईडी बदलने के साथ अद्यतन करें :
db.Entry(order).State = EntityState.Unchanged;
order.ShippingAddress = "Germany"; // will be UPDATED
order.OrderedByUserId = 3; // will be UPDATED
order.OrderedByUser.Id = 2; // will be IGNORED
order.OrderedByUser.FirstName = "William (CHANGED)"; // will be IGNORED
order.OrderPositions[0].Id = 3; // will be IGNORED
order.OrderPositions[0].ArticleNo = "K-1234 (CHANGED)"; // will be IGNORED
order.OrderPositions.Add(new OrderPos { ArticleNo = "T-5555 (NEW)", Quantity = 5 }); // will be INSERTED
db.SaveChanges();
// Will generate SQL in 2 Calls:
// INSERT INTO [OrderPositions] ([ArticleNo], [OrderId], [Quantity]) VALUES ('T-5555', 1, 5)
// UPDATE [Orders] SET [OrderedByUserId] = 3, [ShippingAddress] = 'Germany' WHERE [Id] = 1
अटैच के साथ संदर्भ-आईडी बदलने के साथ अपडेट करें :
db.Attach(order);
order.ShippingAddress = "Germany"; // will be UPDATED
order.OrderedByUserId = 3; // will be UPDATED
order.OrderedByUser.FirstName = "William (CHANGED)"; // will be UPDATED (on FIRST User!)
order.OrderPositions[0].ArticleNo = "K-1234 (CHANGED)"; // will be UPDATED
order.OrderPositions.Add(new OrderPos { ArticleNo = "T-5555 (NEW)", Quantity = 5 }); // will be INSERTED
db.SaveChanges();
// Will generate SQL in 1 Call:
// UPDATE [OrderPositions] SET [ArticleNo] = 'K-1234' WHERE [Id] = 1
// INSERT INTO [OrderPositions] ([ArticleNo], [OrderId], [Quantity]) VALUES ('T-5555 (NEW)', 1, 5)
// UPDATE [Orders] SET [OrderedByUserId] = 3, [ShippingAddress] = 'Germany' WHERE [Id] = 1
// UPDATE [Users] SET [FirstName] = 'William (CHANGED)' WHERE [Id] = 1
नोट: संदर्भ उपयोगकर्ता 3 करने के लिए बदल दिया जाएगा, लेकिन यह भी उपयोगकर्ता 1 अद्यतन किया जाएगा, मुझे लगता है कि इस वजह से order.OrderedByUser.Id
अपरिवर्तित है (यह अभी भी 1 है)।
निष्कर्ष
EntityState के साथ आपके पास अधिक नियंत्रण है, लेकिन आपको अपने आप से उप-संपत्तियों (दूसरे-स्तर) को अपडेट करना होगा। अटैच के साथ आप सब कुछ अपडेट कर सकते हैं (मुझे लगता है कि सभी स्तरों के गुणों के साथ), लेकिन आपको संदर्भों पर नजर रखनी होगी। उदाहरण के लिए: यदि उपयोगकर्ता (आर्डरबायर्स) एक ड्रॉपडाउन होगा, तो ड्रॉपडाउन के माध्यम से मूल्य बदलना पूरे उपयोगकर्ता-ऑब्जेक्ट को अधिलेखित कर सकता है। इस मामले में मूल ड्रॉपडाउन-वैल्यू को संदर्भ के बजाय अधिलेखित कर दिया जाएगा।
मेरे लिए सबसे अच्छा मामला ऑर्डरेडबाइयर्स जैसी वस्तुओं को शून्य करने के लिए सेट कर रहा है और केवल ऑर्डर को सेट करता है। ऑर्डर किया गया। नए मूल्य पर, यदि मैं केवल संदर्भ बदलना चाहता हूं (चाहे एंटिटीस्टेट या अटैच नहीं है)।
आशा है कि यह मदद करता है, मुझे पता है कि यह बहुत पाठ है: डी