Giá trị mặc định cho các trường Bắt buộc trong di chuyển Khung thực thể?


91

Tôi đã thêm [Required]chú thích dữ liệu vào một trong các mô hình của mình trong ứng dụng ASP.NET MVC . Sau khi tạo quá trình di chuyển, chạy Update-Databaselệnh dẫn đến lỗi sau:

Không thể chèn giá trị NULL vào cột 'Director', bảng 'MOVIES_cf7bad808fa94f89afa2e5dae1161e78.dbo.Movies'; cột không cho phép null. UPDATE không thành công. Các tuyên bố này đã bị chấm dứt.

Điều này là do một số bản ghi có NULL trong Director cột . Làm cách nào để tôi có thể tự động thay đổi các giá trị đó thành một số giám đốc mặc định (giả sử "John Doe")?

Đây là mô hình của tôi:

  public class Movie
    {
        public int ID { get; set; }
        [Required]
        public string Title { get; set; }

        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }

        [Required]
        public string Genre { get; set; }

        [Range(1,100)]
        [DataType(DataType.Currency)]
        public decimal Price { get; set; }

        [StringLength(5)]
        public string Rating { get; set; }

        [Required]     /// <--- NEW
        public string Director { get; set; }
    }

và đây là lần di chuyển mới nhất của tôi:

public partial class AddDataAnnotationsMig : DbMigration
{
    public override void Up()
    {
        AlterColumn("dbo.Movies", "Title", c => c.String(nullable: false));
        AlterColumn("dbo.Movies", "Genre", c => c.String(nullable: false));
        AlterColumn("dbo.Movies", "Rating", c => c.String(maxLength: 5));
        AlterColumn("dbo.Movies", "Director", c => c.String(nullable: false));
    }

    public override void Down()
    {
        AlterColumn("dbo.Movies", "Director", c => c.String());
        AlterColumn("dbo.Movies", "Rating", c => c.String());
        AlterColumn("dbo.Movies", "Genre", c => c.String());
        AlterColumn("dbo.Movies", "Title", c => c.String());
    }
}

Câu trả lời:


74

Nếu tôi nhớ không lầm, một cái gì đó như thế này sẽ hoạt động:

AlterColumn("dbo.Movies", "Director", c => c.String(nullable: false, defaultValueSql: "'John Doe'"));

Lưu ý: Giá trị tham số defaultValueSql được coi như một câu lệnh SQL nguyên văn, vì vậy nếu giá trị bắt buộc thực sự là một chuỗi, như ví dụ John Doe, thì các dấu ngoặc kép được yêu cầu xung quanh giá trị.


9
Tôi cũng nghĩ vậy, nhưng điều đó có vẻ không hiệu quả với các bản ghi hiện có. Vì vậy, tôi vẫn nhận được một lỗi.
Andriy Drozdyuk

@drozzy Có thể đó là lỗi, như ở đây: EF 4.3.1 Migration Exception - AlterColumn defaultValueSql tạo cùng một tên ràng buộc mặc định cho các bảng khác nhau Bạn có thể cập nhật các hàng bằng IS NULLcách kiểm tra truy vấn của mình.
webdeveloper

Thật thú vị, nhưng tôi không chắc mình hiểu họ đang nói gì. Tuy nhiên, nếu đây là một lỗi, thì có, nó sẽ có ý nghĩa.
Andriy Drozdyuk 17/09/12

6
Tôi nghĩ nó nên là: "'John Doe'"- bạn cần sử dụng dấu ngoặc kép SQL.
Sean

1
@webdeveloper, tôi không nghĩ đó là lỗi, tại sao lại AlterColumncập nhật các giá trị hiện tại? Nó là một lệnh DDL (không phải DML).
Anton

110

Ngoài câu trả lời từ @webdeveloper và @Pushpendra, bạn cần thêm các bản cập nhật vào quá trình di chuyển của mình theo cách thủ công để cập nhật các hàng hiện có. Ví dụ:

public override void Up()
{
    Sql("UPDATE [dbo].[Movies] SET Title = 'No Title' WHERE Title IS NULL");
    AlterColumn("dbo.Movies", "Title", c => c.String(nullable: false,defaultValue:"MyTitle"));
}

Điều này là do AlterColumntạo ra DDL để đặt giá trị mặc định của cột thành một số giá trị cụ thể trong đặc tả bảng. DDL không ảnh hưởng đến các hàng hiện có trong cơ sở dữ liệu.

Bạn thực sự đang thực hiện hai thay đổi cùng một lúc (đặt mặc định và làm cho cột KHÔNG ĐỦ) và mỗi thay đổi trong số chúng đều hợp lệ riêng lẻ, nhưng vì bạn đang thực hiện hai thay đổi cùng một lúc, bạn có thể mong đợi hệ thống ' một cách thông minh 'nhận ra ý định của bạn và đặt tất cả các NULLgiá trị thành giá trị mặc định, nhưng đây không phải là điều được mong đợi mọi lúc.

Giả sử bạn chỉ đặt giá trị mặc định cho cột và không làm cho nó KHÔNG ĐỦ. Rõ ràng là bạn không mong đợi tất cả các bản ghi NULL được cập nhật với giá trị mặc định mà bạn cung cấp.

Vì vậy, theo ý kiến ​​của tôi, đây không phải là một lỗi và tôi không muốn EF cập nhật dữ liệu của mình theo những cách mà tôi không yêu cầu EF phải làm. Nhà phát triển có trách nhiệm hướng dẫn hệ thống về những việc cần làm với dữ liệu.


17
Đối với những người tìm câu trả lời này thông qua google: Tôi vừa thử điều này trong EF6 và tuyên bố cập nhật dường như không còn cần thiết (nữa). Tôi đoán họ coi đó là một lỗi sau khi tất cả.
EPLKleijntjens

3
Tôi cũng có thể bảo đảm cho điều đó. Nếu bạn cần một giá trị mặc định ngay cả cho một trường nullable, chỉ cần thay đổi nó thành not-nullable trước với một giá trị mặc định, sau đó thay đổi nó trở lại nullable. Rất thuận tiện cho khi bạn thêm một lĩnh vực không nullable để một lớp con :)
Wouter Schut

1
Giải thích tại chỗ. AlterColumn () chỉ thay đổi định nghĩa cột. Nó không ảnh hưởng đến bản ghi hiện có nào
Korayem

10
public partial class AddDataAnnotationsMig : DbMigration
{
    public override void Up()
    {
        AlterColumn("dbo.Movies", "Title", c => c.String(nullable: false,defaultValue:"MyTitle"));
        AlterColumn("dbo.Movies", "Genre", c => c.String(nullable: false,defaultValue:"Genre"));
        AlterColumn("dbo.Movies", "Rating", c => c.String(maxLength: 5));
        AlterColumn("dbo.Movies", "Director", c => c.String(nullable: false,defaultValue:"Director"));

    }

    public override void Down()
    {       
        AlterColumn("dbo.Movies", "Director", c => c.String());
        AlterColumn("dbo.Movies", "Rating", c => c.String());
        AlterColumn("dbo.Movies", "Genre", c => c.String());
        AlterColumn("dbo.Movies", "Title", c => c.String());       
    }
}

2
Ừm ... cảm ơn, nhưng câu trả lời đó khác với câu trả lời của @ webdeveloper như thế nào?
Andriy Drozdyuk 17/09/12

1
nó không cho bạn biết bạn phải thêm thông số giá trị mặc định ở đâu
Pushpendra

1
@Pushpendra, thật buồn cười là các nhà phát triển có xu hướng quên rằng ngày xưa, họ không biết nhiều. Tôi thích câu trả lời chi tiết đáp ứng tất cả các cấp. Công việc tuyệt vời!
hữu íchBee

5

không chắc liệu tùy chọn này có luôn tồn tại hay không nhưng chỉ gặp sự cố tương tự, nhận thấy rằng tôi có thể đặt giá trị mặc định mà không cần chạy bất kỳ bản cập nhật thủ công nào bằng cách sử dụng cách sau

defaultValueSql: "'NY'"

Tôi đã gặp lỗi khi giá trị được cung cấp "NY"sau đó tôi nhận ra rằng họ đang mong đợi một giá trị SQL giống như "GETDATE()"vậy nên tôi đã thử "'NY'"và điều đó đã xảy ra

toàn bộ dòng trông như thế này

AddColumn("TABLE_NAME", "State", c => c.String(maxLength: 2, nullable: false, defaultValueSql: "'NY'"));

Nhờ câu trả lời này , tôi đã đi đúng hướng


2

Tôi thấy rằng chỉ cần sử dụng Trình khởi tạo thuộc tính tự động trên thuộc tính thực thể là đủ để hoàn thành công việc.

Ví dụ:

public class Thing {
    public bool IsBigThing { get; set; } = false;
}

2
Đó là một câu trả lời tốt (đã giúp tôi), nhưng điều này không thêm giá trị mặc định trong cơ sở dữ liệu, nó đặt giá trị trong mã.
chris31389

phải nó không thêm giá trị mặc định trong cơ sở dữ liệu sau khi chnages di chuyển
Chetan Chaudhari

2

Nhiều phản hồi khác tập trung vào cách can thiệp thủ công khi những vấn đề này xảy ra.

Sau khi tạo Di chuyển, hãy thực hiện một trong các thay đổi sau đối với quá trình di chuyển:

  1. Sửa đổi định nghĩa Cột để bao gồm câu lệnh defaultValue hoặc defaultSql:
    AlterColumn("dbo.Movies", "Director", c => c.String(nullable: false, default: ""));

  2. Chèn câu lệnh SQL để điền trước các cột hiện có, trước cột AlterColumn:
    Sql("UPDATE dbo.Movies SET Director = '' WHERE Director IS NULL");

Hãy nhớ rằng các thay đổi thủ công được áp dụng cho tập lệnh di chuyển sẽ bị ghi đè nếu bạn mở đầu lại quá trình di chuyển. Đối với giải pháp đầu tiên, khá dễ dàng mở rộng EF để tự động xác định giá trị mặc định trên một trường như một phần của quá trình tạo di chuyển.

LƯU Ý: EF không tự động thực hiện việc này cho bạn vì việc triển khai giá trị mặc định sẽ khác nhau đối với mỗi nhà cung cấp RDBMS, nhưng cũng vì các giá trị mặc định có ít ý nghĩa hơn trong thời gian chạy EF thuần túy vì mỗi lần chèn hàng sẽ cung cấp giá trị hiện tại cho mỗi thuộc tính, ngay cả khi nó là null, vì vậy ràng buộc giá trị mặc định không bao giờ được đánh giá.
Câu lệnh AlterColumn này là lần duy nhất mà ràng buộc mặc định có hiệu lực, tôi đoán điều này trở thành mức ưu tiên thấp hơn cho nhóm thiết kế Triển khai Di chuyển Máy chủ SQL.

Giải pháp sau kết hợp ký hiệu thuộc tính, quy ước cấu hình mô hình và chú thích cột để chuyển siêu dữ liệu đến trình tạo mã Di chuyển tùy chỉnh. Các bước 1 và 2 có thể được thay thế bằng ký hiệu thông thạo cho từng trường bị ảnh hưởng nếu bạn không sử dụng ký hiệu thuộc tính.
Có rất nhiều kỹ thuật chơi ở đây, hãy thoải mái sử dụng một số hoặc tất cả, tôi hy vọng rằng sẽ có giá trị cho mọi người ở đây


  1. Khai báo giá trị mặc định
    Tạo hoặc chuyển mục đích lại một thuộc tính hiện có để xác định giá trị mặc định để sử dụng, trong ví dụ này, chúng tôi sẽ tạo một thuộc tính mới có tên là DefaultValue kế thừa từ ComponentModel.DefaultValueAttribute, vì cách sử dụng là trực quan và có khả năng tồn tại cơ sở mã đã triển khai thuộc tính này. Với cách triển khai này, bạn chỉ cần sử dụng thuộc tính cụ thể này để truy cập vào DefaultValueSql hữu ích cho ngày tháng và các trường hợp tùy chỉnh khác.

    Thực hiện

    [DefaultValue("Insert DefaultValue Here")]
    [Required]     /// <--- NEW
    public string Director { get; set; }
    
    // Example of default value sql
    [DefaultValue(DefaultValueSql: "GetDate()")]
    [Required]
    public string LastModified { get; set; }

    Định nghĩa Attrribute

    namespace EFExtensions
    {
        /// <summary>
        /// Specifies the default value for a property but allows a custom SQL statement to be provided as well. <see cref="MiniTuber.Database.Conventions.DefaultValueConvention"/>
        /// </summary>
        public class DefaultValueAttribute : System.ComponentModel.DefaultValueAttribute
        {
            /// <summary>
            /// Specifies the default value for a property but allows a custom SQL statement to be provided as well. <see cref="MiniTuber.Database.Conventions.DefaultValueConvention"/>
            /// </summary>
            public DefaultValueAttribute() : base("")
            {
            }
    
            /// <i
            /// <summary>
            /// Optional SQL to use to specify the default value.
            /// </summary>
            public string DefaultSql { get; set; }
    
            /// <summary>
            /// Initializes a new instance of the System.ComponentModel.DefaultValueAttribute
            /// class using a Unicode character.
            /// </summary>
            /// <param name="value">
            /// A Unicode character that is the default value.
            /// </param>
            public DefaultValueAttribute(char value) : base(value) { }
    
            /// <summary>
            /// Initializes a new instance of the System.ComponentModel.DefaultValueAttribute
            /// class using an 8-bit unsigned integer.
            /// </summary>
            /// <param name="value">
            /// An 8-bit unsigned integer that is the default value.
            /// </param>
            public DefaultValueAttribute(byte value) : base(value) { }
    
            /// <summary>
            /// Initializes a new instance of the System.ComponentModel.DefaultValueAttribute
            /// class using a 16-bit signed integer.
            /// </summary>
            /// <param name="value">
            /// A 16-bit signed integer that is the default value.
            /// </param>
            public DefaultValueAttribute(short value) : base(value) { }
    
            /// <summary>
            /// Initializes a new instance of the System.ComponentModel.DefaultValueAttribute
            /// class using a 32-bit signed integer.
            /// </summary>
            /// <param name="value">
            /// A 32-bit signed integer that is the default value.
            /// </param>
            public DefaultValueAttribute(int value) : base(value) { }
    
            /// <summary>
            /// Initializes a new instance of the System.ComponentModel.DefaultValueAttribute
            /// class using a 64-bit signed integer.
            /// </summary>
            /// <param name="value">
            /// A 64-bit signed integer that is the default value.
            /// </param>
            public DefaultValueAttribute(long value) : base(value) { }
    
            /// <summary>
            /// Initializes a new instance of the System.ComponentModel.DefaultValueAttribute
            /// class using a single-precision floating point number.
            /// </summary>
            /// <param name="value">
            /// A single-precision floating point number that is the default value.
            /// </param>
            public DefaultValueAttribute(float value) : base(value) { }
    
            /// <summary>
            /// Initializes a new instance of the System.ComponentModel.DefaultValueAttribute
            /// class using a double-precision floating point number.
            /// </summary>
            /// <param name="value">
            /// A double-precision floating point number that is the default value.
            /// </param>
            public DefaultValueAttribute(double value) : base(value) { }
    
            /// <summary>
            /// Initializes a new instance of the System.ComponentModel.DefaultValueAttribute
            /// class using a System.Boolean value.
            /// </summary>
            /// <param name="value">
            /// A System.Boolean that is the default value.
            /// </param>
            public DefaultValueAttribute(bool value) : base(value) { }
    
            /// <summary>
            /// Initializes a new instance of the System.ComponentModel.DefaultValueAttribute
            /// class using a System.String.
            /// </summary>
            /// <param name="value">
            /// A System.String that is the default value.
            /// </param>
            public DefaultValueAttribute(string value) : base(value) { }
    
            /// <summary>
            /// Initializes a new instance of the System.ComponentModel.DefaultValueAttribute
            /// class.
            /// </summary>
            /// <param name="value">
            /// An System.Object that represents the default value.
            /// </param>
            public DefaultValueAttribute(object value) : base(value) { }
    
            /// /// <inheritdoc/>
            /// Initializes a new instance of the System.ComponentModel.DefaultValueAttribute
            /// class, converting the specified value to the specified type, and using an invariant
            /// culture as the translation context.
            /// </summary>
            /// <param name="type">
            /// A System.Type that represents the type to convert the value to.
            /// </param>
            /// <param name="value">
            /// A System.String that can be converted to the type using the System.ComponentModel.TypeConverter
            /// for the type and the U.S. English culture.
            /// </param>
            public DefaultValueAttribute(Type type, string value) : base(value) { }
        }
    }
  2. Tạo quy ước để đưa giá trị mặc định vào các chú thích cột Chú thích
    cột được sử dụng để chuyển siêu dữ liệu tùy chỉnh về các cột đến trình tạo tập lệnh di chuyển.
    Sử dụng quy ước để thực hiện điều này chứng tỏ sức mạnh đằng sau ký hiệu Thuộc tính để đơn giản hóa cách siêu dữ liệu thông thạo có thể được xác định và thao tác cho nhiều thuộc tính thay vì chỉ định nó riêng lẻ cho từng trường.

    namespace EFExtensions
    {
    
        /// <summary>
        /// Implement SQL Default Values from System.ComponentModel.DefaultValueAttribute
        /// </summary>
        public class DefaultValueConvention : Convention
        {
            /// <summary>
            /// Annotation Key to use for Default Values specified directly as an object
            /// </summary>
            public const string DirectValueAnnotationKey = "DefaultValue";
            /// <summary>
            /// Annotation Key to use for Default Values specified as SQL Strings
            /// </summary>
            public const string SqlValueAnnotationKey = "DefaultSql";
    
            /// <summary>
            /// Implement SQL Default Values from System.ComponentModel.DefaultValueAttribute
            /// </summary>
            public DefaultValueConvention()
            {
                // Implement SO Default Value Attributes first
                this.Properties()
                        .Where(x => x.HasAttribute<EFExtensions.DefaultValueAttribute>())
                        .Configure(c => c.HasColumnAnnotation(
                            c.GetAttribute<EFExtensions.DefaultValueAttribute>().GetDefaultValueAttributeKey(),
                            c.GetAttribute<EFExtensions.DefaultValueAttribute>().GetDefaultValueAttributeValue()
                            ));
    
                // Implement Component Model Default Value Attributes, but only if it is not the SO implementation
                this.Properties()
                        .Where(x => x.HasAttribute<System.ComponentModel.DefaultValueAttribute>())
                        .Where(x => !x.HasAttribute<MiniTuber.DataAnnotations.DefaultValueAttribute>())
                        .Configure(c => c.HasColumnAnnotation(
                            DefaultValueConvention.DirectValueAnnotationKey, 
                            c.GetAttribute<System.ComponentModel.DefaultValueAttribute>().Value
                            ));
            }
        }
    
        /// <summary>
        /// Extension Methods to simplify the logic for building column annotations for Default Value processing
        /// </summary>
        public static partial class PropertyInfoAttributeExtensions
        {
            /// <summary>
            /// Wrapper to simplify the lookup for a specific attribute on a property info.
            /// </summary>
            /// <typeparam name="T">Type of attribute to lookup</typeparam>
            /// <param name="self">PropertyInfo to inspect</param>
            /// <returns>True if an attribute of the requested type exists</returns>
            public static bool HasAttribute<T>(this PropertyInfo self) where T : Attribute
            {
                return self.GetCustomAttributes(false).OfType<T>().Any();
            }
    
            /// <summary>
            /// Wrapper to return the first attribute of the specified type
            /// </summary>
            /// <typeparam name="T">Type of attribute to return</typeparam>
            /// <param name="self">PropertyInfo to inspect</param>
            /// <returns>First attribuite that matches the requested type</returns>
            public static T GetAttribute<T>(this System.Data.Entity.ModelConfiguration.Configuration.ConventionPrimitivePropertyConfiguration self) where T : Attribute
            {
                return self.ClrPropertyInfo.GetCustomAttributes(false).OfType<T>().First();
            }
    
            /// <summary>
            /// Helper to select the correct DefaultValue annotation key based on the attribute values
            /// </summary>
            /// <param name="self"></param>
            /// <returns></returns>
            public static string GetDefaultValueAttributeKey(this EFExtensions.DefaultValueAttribute self)
            {
                return String.IsNullOrWhiteSpace(self.DefaultSql) ? DefaultValueConvention.DirectValueAnnotationKey : DefaultValueConvention.SqlValueAnnotationKey;
            }
    
            /// <summary>
            /// Helper to select the correct attribute property to send as a DefaultValue annotation value
            /// </summary>
            /// <param name="self"></param>
            /// <returns></returns>
            public static object GetDefaultValueAttributeValue(this EFExtensions.DefaultValueAttribute self)
            {
                return String.IsNullOrWhiteSpace(self.DefaultSql) ? self.Value : self.DefaultSql;
            }
        }
    
    }
  3. Thêm quy ước vào DbContext
    Có nhiều cách để đạt được điều này, tôi muốn khai báo các quy ước như là bước tùy chỉnh đầu tiên trong logic ModelCreation của tôi, điều này sẽ nằm trong lớp DbContext của bạn.

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        // Use our new DefaultValueConvention
        modelBuilder.Conventions.Add<EFExtensions.DefaultValueConvention>();
    
        // My personal favourites ;)
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
    
    }
  4. Ghi đè MigrationCodeGenerator
    Bây giờ các chú thích đó đã được áp dụng cho các định nghĩa cột trong mô hình, chúng tôi cần sửa đổi trình tạo tập lệnh di chuyển để sử dụng các chú thích đó. Đối với điều này, chúng tôi sẽ kế thừa từ System.Data.Entity.Migrations.Design.CSharpMigrationCodeGeneratorvì chúng tôi chỉ cần đưa vào một lượng thay đổi tối thiểu.
    Khi chúng tôi đã xử lý xong chú thích tùy chỉnh của mình, chúng tôi cần xóa chú thích đó khỏi định nghĩa cột để ngăn nó được tuần tự hóa đến đầu ra cuối cùng.

    Xem mã lớp cơ sở để khám phá cách sử dụng khác: http://entityframework.codeplex.com/sourcecontrol/latest#src/EntityFramework/Migrations/Design/CSharpMigrationCodeGenerator.cs

    namespace EFExtensions
    {
        /// <summary>
        /// Implement DefaultValue constraint definition in Migration Scripts.
        /// </summary>
        /// <remarks>
        /// Original guide that provided inspiration for this https://romiller.com/2012/11/30/code-first-migrations-customizing-scaffolded-code/
        /// </remarks>
        public class CustomCodeGenerator : System.Data.Entity.Migrations.Design.CSharpMigrationCodeGenerator
        {
            /// <summary>
            /// Inject Default values from the DefaultValue attribute, if the DefaultValueConvention has been enabled.
            /// </summary>
            /// <seealso cref="DefaultValueConvention"/>
            /// <param name="column"></param>
            /// <param name="writer"></param>
            /// <param name="emitName"></param>
            protected override void Generate(ColumnModel column, IndentedTextWriter writer, bool emitName = false)
            {
                var annotations = column.Annotations?.ToList();
                if (annotations != null && annotations.Any())
                {
                    for (int index = 0; index < annotations.Count; index ++)
                    {
                        var annotation = annotations[index];
                        bool handled = true;
    
                        try
                        {
                            switch (annotation.Key)
                            {
                                case DefaultValueConvention.SqlValueAnnotationKey:
                                    if (annotation.Value?.NewValue != null)
                                    {
                                        column.DefaultValueSql = $"{annotation.Value.NewValue}";
                                    }
                                    break;
                                case DefaultValueConvention.DirectValueAnnotationKey:
                                    if (annotation.Value?.NewValue != null)
                                    {
                                        column.DefaultValue = Convert.ChangeType(annotation.Value.NewValue, column.ClrType);
                                    }
                                    break;
                                default:
                                    handled = false;
                                    break;
                            }
                        }
                        catch(Exception ex)
                        {
                            // re-throw with specific debug information
                            throw new ApplicationException($"Failed to Implement Column Annotation for column: {column.Name} with key: {annotation.Key} and new value: {annotation.Value.NewValue}", ex);
                        }
    
                        if(handled)
                        {
                            // remove the annotation, it has been applied
                            column.Annotations.Remove(annotation.Key);
                        }
                    }
                }
                base.Generate(column, writer, emitName);
            }
    
            /// <summary>
            /// Generates class summary comments and default attributes
            /// </summary>
            /// <param name="writer"> Text writer to add the generated code to. </param>
            /// <param name="designer"> A value indicating if this class is being generated for a code-behind file. </param>
            protected override void WriteClassAttributes(IndentedTextWriter writer, bool designer)
            {
                writer.WriteLine("/// <summary>");
                writer.WriteLine("/// Definition of the Migration: {0}", this.ClassName);
                writer.WriteLine("/// </summary>");
                writer.WriteLine("/// <remarks>");
                writer.WriteLine("/// Generated Time: {0}", DateTime.Now);
                writer.WriteLine("/// Generated By: {0}", Environment.UserName);
                writer.WriteLine("/// </remarks>");
                base.WriteClassAttributes(writer, designer);
            }
    
    
        }
    }
  5. Đăng ký CustomCodeGenerator
    Bước cuối cùng, trong tệp Cấu hình DbMigration, chúng ta cần chỉ định Code Generator để sử dụng, hãy tìm Configuration.cs trong thư mục Migration của bạn theo mặc định ...

    internal sealed class Configuration : DbMigrationsConfiguration<YourApplication.Database.Context>
    {
        public Configuration()
        {
            // I recommend that auto-migrations be disabled so that we control
            // the migrations explicitly 
            AutomaticMigrationsEnabled = false;
            CodeGenerator = new EFExtensions.CustomCodeGenerator();
        }
    
        protected override void Seed(YourApplication.Database.Context context)
        {
            //   Your custom seed logic here
        }
    }

2

Kể từ EF Core 2.1, bạn có thể sử dụng MigrationBuilder.UpdateDatađể thay đổi giá trị trước khi thay đổi cột (rõ ràng hơn so với sử dụng SQL thô):

protected override void Up(MigrationBuilder migrationBuilder)
{
    // Change existing NULL values to NOT NULL values
    migrationBuilder.UpdateData(
        table: tableName,
        column: columnName,
        value: valueInsteadOfNull,
        keyColumn: columnName,
        keyValue: null);

    // Change column type to NOT NULL
    migrationBuilder.AlterColumn<ColumnType>(
        table: tableName,
        name: columnName,
        nullable: false,
        oldClrType: typeof(ColumnType),
        oldNullable: true);
}

0

Vì một số lý do, tôi không thể tự giải thích rằng câu trả lời đã được phê duyệt không còn phù hợp với tôi nữa.

Nó hoạt động trên một ứng dụng khác, trên ứng dụng mà tôi đang làm việc thì không.

Vì vậy, một giải pháp thay thế, nhưng khá kém hiệu quả , sẽ là ghi đè Phương thức SaveChanges () như được hiển thị bên dưới. Phương thức này phải nằm trên lớp Context.

    public override int SaveChanges()
    {
        foreach (var entry in ChangeTracker.Entries().Where(entry => entry.Entity.GetType().GetProperty("ColumnName") != null))
        {
            if (entry.State == EntityState.Added)
            {
                entry.Property("ColumnName").CurrentValue = "DefaultValue";
            }
        }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.