समस्या:
मैंने इसे पोमेलो में एक बग (जो प्रतीत होता है) तक सीमित कर दिया है। समस्या यहाँ है:
https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql/issues /801
मुद्दा यह है कि पोमेलो एक defaultValue
बनाता है DateTime
. के लिए संपत्ति और माइग्रेशन उत्पन्न करते समय अन्य संरचनाएं। यदि माइग्रेशन पर एक डिफ़ॉल्ट मान सेट किया गया है, तो यह मूल्य निर्माण रणनीति को ओवरराइड करता है, और SQL तब गलत दिखता है।
समाधान माइग्रेशन जनरेट करना है, और फिर defaultValue
. सेट करने के लिए माइग्रेशन फ़ाइल को मैन्युअल रूप से संशोधित करना है करने के लिए null
(या पूरी लाइन हटा दें)।
उदाहरण के लिए, इसे बदलें:
migrationBuilder.AddColumn<DateTime>(
name: "UpdatedTime",
table: "SomeTable",
nullable: false,
defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)))
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.ComputedColumn);
इसके लिए:
migrationBuilder.AddColumn<DateTime>(
name: "UpdatedTime",
table: "SomeTable",
nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.ComputedColumn);
तब माइग्रेशन स्क्रिप्ट DEFAULT CURRENT_TIMESTAMP
के साथ सही SQL को थूक देगी TIMESTAMP
. के लिए . अगर आप [Column(TypeName = "TIMESTAMP")]
. को हटाते हैं विशेषता, यह एक datetime(6)
. का उपयोग करेगा कॉलम और थूक दें DEFAULT CURRENT_TIMESTAMP(6)
।
समाधान:
मैं एक वर्कअराउंड के साथ आया हूं जो क्रिएटेड टाइम (डेटाबेस द्वारा केवल INSERT पर अपडेट किया गया) और अपडेटेड टाइम (डेटाबेस द्वारा केवल INSERT और UPDATE पर अपडेट किया गया) को सही ढंग से लागू करता है।
सबसे पहले, अपनी इकाई को इस प्रकार परिभाषित करें:
public class SomeEntity
{
// Other properties here ...
public DateTime CreatedTime { get; set; }
public DateTime UpdatedTime { get; set; }
}
फिर, निम्नलिखित को OnModelCreating()
में जोड़ें :
protected override void OnModelCreating(ModelBuilder builder)
{
// Other model creating stuff here ...
builder.Entity<SomeEntity>.Property(d => d.CreatedTime).ValueGeneratedOnAdd();
builder.Entity<SomeEntity>.Property(d => d.UpdatedTime).ValueGeneratedOnAddOrUpdate();
builder.Entity<SomeEntity>.Property(d => d.CreatedTime).Metadata.SetBeforeSaveBehavior(PropertySaveBehavior.Ignore);
builder.Entity<SomeEntity>.Property(d => d.CreatedTime).Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Ignore);
builder.Entity<SomeEntity>.Property(d => d.UpdatedTime).Metadata.SetBeforeSaveBehavior(PropertySaveBehavior.Ignore);
builder.Entity<SomeEntity>.Property(d => d.UpdatedTime).Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Ignore);
}
यह एक आदर्श प्रारंभिक माइग्रेशन उत्पन्न करता है (जहां migrationBuilder.CreateTable
प्रयोग किया जाता है), और अपेक्षित SQL उत्पन्न करता है:
`created_time` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
`updated_time` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
यह चाहिए माइग्रेशन पर भी काम करते हैं जो मौजूदा तालिकाओं को अपडेट करते हैं, लेकिन सुनिश्चित करें कि defaultValue
हमेशा शून्य होता है।
SetBeforeSaveBehavior
और SetAfterSaveBehavior
लाइनें EF को कभी भी बनाए गए समय को डिफ़ॉल्ट मान के साथ अधिलेखित करने का प्रयास करने से रोकती हैं। यह प्रभावी रूप से बनाए गए और अपडेट किए गए कॉलम को केवल ईएफ के दृष्टिकोण से पढ़ने के लिए बनाता है, जिससे डेटाबेस को सभी काम करने की इजाजत मिलती है।
आप इसे एक इंटरफ़ेस और एक्सटेंशन विधि में भी निकाल सकते हैं:
public interface ITimestampedEntity
{
DateTime CreatedTime { get; set; }
DateTime UpdatedTime { get; set; }
}
public static EntityTypeBuilder<TEntity> UseTimestampedProperty<TEntity>(this EntityTypeBuilder<TEntity> entity) where TEntity : class, ITimestampedEntity
{
entity.Property(d => d.CreatedTime).ValueGeneratedOnAdd();
entity.Property(d => d.UpdatedTime).ValueGeneratedOnAddOrUpdate();
entity.Property(d => d.CreatedTime).SetBeforeSaveBehavior(PropertySaveBehavior.Ignore);
entity.Property(d => d.CreatedTime).SetAfterSaveBehavior(PropertySaveBehavior.Ignore);
entity.Property(d => d.UpdatedTime).SetBeforeSaveBehavior(PropertySaveBehavior.Ignore);
entity.Property(d => d.UpdatedTime).SetAfterSaveBehavior(PropertySaveBehavior.Ignore);
return entity;
}
फिर इंटरफ़ेस को अपनी सभी टाइमस्टैम्प वाली इकाइयों पर लागू करें:
public class SomeEntity : ITimestampedEntity
{
// Other properties here ...
public DateTime CreatedTime { get; set; }
public DateTime UpdatedTime { get; set; }
}
यह आपको OnModelCreating()
. के भीतर से इकाई को सेट करने की अनुमति देता है इस तरह:
protected override void OnModelCreating(ModelBuilder builder)
{
// Other model creating stuff here ...
builder.Entity<SomeTimestampedEntity>().UseTimestampedProperty();
}