Có cách nào "thanh lịch" để cung cấp cho tài sản cụ thể một giá trị mặc định?
Có thể bởi DataAnnotations, đại loại như:
[DefaultValue("true")]
public bool Active { get; set; }
Cảm ơn bạn.
public bool Inactive { get; set; }
😉
Có cách nào "thanh lịch" để cung cấp cho tài sản cụ thể một giá trị mặc định?
Có thể bởi DataAnnotations, đại loại như:
[DefaultValue("true")]
public bool Active { get; set; }
Cảm ơn bạn.
public bool Inactive { get; set; }
😉
Câu trả lời:
Bạn có thể làm điều đó bằng cách chỉnh sửa thủ công mã di chuyển đầu tiên:
public override void Up()
{
AddColumn("dbo.Events", "Active", c => c.Boolean(nullable: false, defaultValue: true));
}
Active
để true
khi tạo một Event
đối tượng là tốt. Giá trị mặc định luôn nằm false
trên một thuộc tính bool không null, vì vậy trừ khi thay đổi, đây là khung thực thể sẽ lưu vào db. Hay tôi đang thiếu một cái gì đó?
Đã được một lúc, nhưng để lại một ghi chú cho người khác. Tôi đã đạt được những gì cần thiết với một thuộc tính và tôi đã trang trí các trường lớp mô hình của mình với thuộc tính đó như tôi muốn.
[SqlDefaultValue(DefaultValue = "getutcdate()")]
public DateTime CreatedDateUtc { get; set; }
Có sự giúp đỡ của 2 bài viết này:
Tôi đã làm gì:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class SqlDefaultValueAttribute : Attribute
{
public string DefaultValue { get; set; }
}
modelBuilder.Conventions.Add( new AttributeToColumnAnnotationConvention<SqlDefaultValueAttribute, string>("SqlDefaultValue", (p, attributes) => attributes.Single().DefaultValue));
private void SetAnnotatedColumn(ColumnModel col)
{
AnnotationValues values;
if (col.Annotations.TryGetValue("SqlDefaultValue", out values))
{
col.DefaultValueSql = (string)values.NewValue;
}
}
Sau đó, trong hàm tạo Cấu hình di chuyển, hãy đăng ký trình tạo SQL tùy chỉnh.
SetSqlGenerator("System.Data.SqlClient", new CustomMigrationSqlGenerator());
[SqlDefaultValue(DefaultValue = "getutcdate()")]
vào mọi thực thể. 1) Chỉ cần xóa modelBuilder.Conventions.Add( new AttributeToColumnAnnotationConvention<SqlDefaultValueAttribute, string>("SqlDefaultValue", (p, attributes) => attributes.Single().DefaultValue));
2) ThêmmodelBuilder.Properties().Where(x => x.PropertyType == typeof(DateTime)).Configure(c => c.HasColumnType("datetime2").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed).HasColumnAnnotation("SqlDefaultValue", "getdate()"));
Các câu trả lời trên thực sự có ích, nhưng chỉ cung cấp một phần của giải pháp. Vấn đề chính là ngay khi bạn xóa thuộc tính Giá trị mặc định, ràng buộc trên cột trong cơ sở dữ liệu sẽ không bị xóa. Vì vậy, giá trị mặc định trước đó sẽ vẫn ở trong cơ sở dữ liệu.
Đây là một giải pháp đầy đủ cho vấn đề, bao gồm loại bỏ các ràng buộc SQL về loại bỏ thuộc tính. Tôi cũng đang sử dụng lại DefaultValue
thuộc tính gốc của .NET Framework .
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
[DefaultValue("getutcdate()")]
public DateTime CreatedOn { get; set; }
Để làm việc này, bạn cần cập nhật các tập tin IdentityModels.cs và Configuration.cs
Thêm / cập nhật phương thức này trong ApplicationDbContext
lớp của bạn
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
var convention = new AttributeToColumnAnnotationConvention<DefaultValueAttribute, string>("SqlDefaultValue", (p, attributes) => attributes.SingleOrDefault().Value.ToString());
modelBuilder.Conventions.Add(convention);
}
Cập nhật Configuration
trình xây dựng lớp của bạn bằng cách đăng ký trình tạo Sql tùy chỉnh, như sau:
internal sealed class Configuration : DbMigrationsConfiguration<ApplicationDbContext>
{
public Configuration()
{
// DefaultValue Sql Generator
SetSqlGenerator("System.Data.SqlClient", new DefaultValueSqlServerMigrationSqlGenerator());
}
}
Tiếp theo, thêm lớp trình tạo Sql tùy chỉnh (bạn có thể thêm nó vào tệp Cấu hình.cs hoặc một tệp riêng)
internal class DefaultValueSqlServerMigrationSqlGenerator : SqlServerMigrationSqlGenerator
{
private int dropConstraintCount = 0;
protected override void Generate(AddColumnOperation addColumnOperation)
{
SetAnnotatedColumn(addColumnOperation.Column, addColumnOperation.Table);
base.Generate(addColumnOperation);
}
protected override void Generate(AlterColumnOperation alterColumnOperation)
{
SetAnnotatedColumn(alterColumnOperation.Column, alterColumnOperation.Table);
base.Generate(alterColumnOperation);
}
protected override void Generate(CreateTableOperation createTableOperation)
{
SetAnnotatedColumns(createTableOperation.Columns, createTableOperation.Name);
base.Generate(createTableOperation);
}
protected override void Generate(AlterTableOperation alterTableOperation)
{
SetAnnotatedColumns(alterTableOperation.Columns, alterTableOperation.Name);
base.Generate(alterTableOperation);
}
private void SetAnnotatedColumn(ColumnModel column, string tableName)
{
AnnotationValues values;
if (column.Annotations.TryGetValue("SqlDefaultValue", out values))
{
if (values.NewValue == null)
{
column.DefaultValueSql = null;
using (var writer = Writer())
{
// Drop Constraint
writer.WriteLine(GetSqlDropConstraintQuery(tableName, column.Name));
Statement(writer);
}
}
else
{
column.DefaultValueSql = (string)values.NewValue;
}
}
}
private void SetAnnotatedColumns(IEnumerable<ColumnModel> columns, string tableName)
{
foreach (var column in columns)
{
SetAnnotatedColumn(column, tableName);
}
}
private string GetSqlDropConstraintQuery(string tableName, string columnName)
{
var tableNameSplittedByDot = tableName.Split('.');
var tableSchema = tableNameSplittedByDot[0];
var tablePureName = tableNameSplittedByDot[1];
var str = $@"DECLARE @var{dropConstraintCount} nvarchar(128)
SELECT @var{dropConstraintCount} = name
FROM sys.default_constraints
WHERE parent_object_id = object_id(N'{tableSchema}.[{tablePureName}]')
AND col_name(parent_object_id, parent_column_id) = '{columnName}';
IF @var{dropConstraintCount} IS NOT NULL
EXECUTE('ALTER TABLE {tableSchema}.[{tablePureName}] DROP CONSTRAINT [' + @var{dropConstraintCount} + ']')";
dropConstraintCount = dropConstraintCount + 1;
return str;
}
}
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
thuộc tính không? Nếu vậy, tại sao? Trong các thử nghiệm của tôi, nó dường như không có tác dụng gì.
Thuộc tính mô hình của bạn không phải là 'thuộc tính tự động' Mặc dù điều đó dễ dàng hơn. Và thuộc tính DefaultValue thực sự chỉ là siêu dữ liệu thông tin Câu trả lời được chấp nhận ở đây là một thay thế cho phương pháp xây dựng.
public class Track
{
private const int DEFAULT_LENGTH = 400;
private int _length = DEFAULT_LENGTH;
[DefaultValue(DEFAULT_LENGTH)]
public int LengthInMeters {
get { return _length; }
set { _length = value; }
}
}
so với
public class Track
{
public Track()
{
LengthInMeters = 400;
}
public int LengthInMeters { get; set; }
}
Điều này sẽ chỉ hoạt động cho các ứng dụng tạo và tiêu thụ dữ liệu bằng cách sử dụng lớp cụ thể này. Thông thường đây không phải là vấn đề nếu mã truy cập dữ liệu được tập trung. Để cập nhật giá trị trên tất cả các ứng dụng, bạn cần định cấu hình nguồn dữ liệu để đặt giá trị mặc định. Câu trả lời của Devi cho thấy cách nó có thể được thực hiện bằng cách sử dụng di chuyển, sql hoặc bất kỳ ngôn ngữ nào mà nguồn dữ liệu của bạn nói.
Những gì tôi đã làm, tôi đã khởi tạo các giá trị trong hàm tạo của thực thể
Lưu ý: Thuộc tính DefaultValue sẽ không tự động đặt các giá trị thuộc tính của bạn, bạn phải tự làm điều đó
Sau khi nhận xét @SedatKapanoglu, tôi đang thêm tất cả các phương pháp tiếp cận hiệu quả, bởi vì anh ấy đã đúng, chỉ sử dụng API trôi chảy không hoạt động.
1- Tạo trình tạo mã tùy chỉnh và ghi đè Tạo cho CộtModel.
public class ExtendedMigrationCodeGenerator : CSharpMigrationCodeGenerator
{
protected override void Generate(ColumnModel column, IndentedTextWriter writer, bool emitName = false)
{
if (column.Annotations.Keys.Contains("Default"))
{
var value = Convert.ChangeType(column.Annotations["Default"].NewValue, column.ClrDefaultValue.GetType());
column.DefaultValue = value;
}
base.Generate(column, writer, emitName);
}
}
2- Chỉ định trình tạo mã mới:
public sealed class Configuration : DbMigrationsConfiguration<Data.Context.EfSqlDbContext>
{
public Configuration()
{
CodeGenerator = new ExtendedMigrationCodeGenerator();
AutomaticMigrationsEnabled = false;
}
}
3- Sử dụng api trôi chảy để tạo Chú thích:
public static void Configure(DbModelBuilder builder){
builder.Entity<Company>().Property(c => c.Status).HasColumnAnnotation("Default", 0);
}
Thật đơn giản! Chỉ cần chú thích với yêu cầu.
[Required]
public bool MyField { get; set; }
di chuyển kết quả sẽ là:
migrationBuilder.AddColumn<bool>(
name: "MyField",
table: "MyTable",
nullable: false,
defaultValue: false);
Nếu bạn muốn true, thay đổi defaultValue thành true trong quá trình di chuyển trước khi cập nhật cơ sở dữ liệu
true
gì?
Tôi thừa nhận rằng cách tiếp cận của tôi thoát khỏi toàn bộ khái niệm "Code First". Nhưng nếu bạn có khả năng chỉ thay đổi giá trị mặc định trong bảng ... thì đơn giản hơn nhiều so với độ dài mà bạn phải trải qua ở trên ... Tôi chỉ quá lười biếng để làm tất cả công việc đó!
Có vẻ như ý tưởng ban đầu của áp phích sẽ hoạt động:
[DefaultValue(true)]
public bool IsAdmin { get; set; }
Tôi nghĩ rằng họ đã phạm sai lầm khi thêm dấu ngoặc kép ... nhưng than ôi không có trực giác như vậy. Các đề xuất khác chỉ là quá nhiều đối với tôi (với điều kiện tôi có các đặc quyền cần thiết để đi vào bảng và thực hiện các thay đổi ... nơi mà không phải mọi nhà phát triển sẽ trong mọi tình huống). Cuối cùng, tôi đã làm theo cách cũ. Tôi đặt giá trị mặc định trong bảng SQL Server ... Ý tôi là thực sự, đã đủ rồi! LƯU Ý: Tôi đã thử nghiệm thêm khi thực hiện thêm cơ sở dữ liệu di chuyển và cập nhật và các thay đổi bị mắc kẹt.
Chỉ cần quá tải hàm tạo mặc định của lớp Model và truyền bất kỳ tham số có liên quan nào mà bạn có thể hoặc không thể sử dụng. Bằng cách này, bạn có thể dễ dàng cung cấp các giá trị mặc định cho các thuộc tính. Dưới đây là một ví dụ.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Aim.Data.Domain
{
[MetadataType(typeof(LoginModel))]
public partial class Login
{
public Login(bool status)
{
this.CreatedDate = DateTime.Now;
this.ModifiedDate = DateTime.Now;
this.Culture = "EN-US";
this.IsDefaultPassword = status;
this.IsActive = status;
this.LoginLogs = new HashSet<LoginLog>();
this.LoginLogHistories = new HashSet<LoginLogHistory>();
}
}
public class LoginModel
{
[Key]
[ScaffoldColumn(false)]
public int Id { get; set; }
[Required]
public string LoginCode { get; set; }
[Required]
public string Password { get; set; }
public string LastPassword { get; set; }
public int UserGroupId { get; set; }
public int FalseAttempt { get; set; }
public bool IsLocked { get; set; }
public int CreatedBy { get; set; }
public System.DateTime CreatedDate { get; set; }
public Nullable<int> ModifiedBy { get; set; }
public Nullable<System.DateTime> ModifiedDate { get; set; }
public string Culture { get; set; }
public virtual ICollection<LoginLog> LoginLogs { get; set; }
public virtual ICollection<LoginLogHistory> LoginLogHistories { get; set; }
}
}
Hãy xem xét bạn có tên lớp là Sản phẩm và bạn có trường IsActive. chỉ cần bạn tạo một constructor:
Public class Products
{
public Products()
{
IsActive = true;
}
public string Field1 { get; set; }
public string Field2 { get; set; }
public bool IsActive { get; set; }
}
Sau đó, giá trị mặc định IsActive của bạn là True!
Chỉnh sửa :
nếu bạn muốn làm điều này với SQL, hãy sử dụng lệnh này:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.IsActive)
.HasDefaultValueSql("true");
}
Trong lõi EF phát hành ngày 27 tháng 6 năm 2016, bạn có thể sử dụng API thông thạo để đặt giá trị mặc định. Đi đến lớp ApplicationDbContext, tìm / tạo tên phương thức OnModelCreating và thêm API thông thạo sau.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<YourTableName>()
.Property(b => b.Active)
.HasDefaultValue(true);
}
Trong .NET Core 3.1, bạn có thể thực hiện các thao tác sau trong lớp mô hình:
public bool? Active { get; set; }
Trong DbContext OnModelCreating, bạn thêm giá trị mặc định.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Foundation>()
.Property(b => b.Active)
.HasDefaultValueSql("1");
base.OnModelCreating(modelBuilder);
}
Kết quả như sau trong cơ sở dữ liệu
Lưu ý: Nếu bạn không có nullable (bool?) Cho tài sản của bạn, bạn sẽ nhận được cảnh báo sau
The 'bool' property 'Active' on entity type 'Foundation' is configured with a database-generated default. This default will always be used for inserts when the property has the value 'false', since this is the CLR default for the 'bool' type. Consider using the nullable 'bool?' type instead so that the default will only be used for inserts when the property value is 'null'.
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;
}
Hmm ... Tôi làm DB trước, và trong trường hợp đó, điều này thực sự dễ dàng hơn rất nhiều. EF6 phải không? Chỉ cần mở mô hình của bạn, nhấp chuột phải vào cột bạn muốn đặt mặc định, chọn thuộc tính và bạn sẽ thấy trường "DefaultValue". Chỉ cần điền vào đó và tiết kiệm. Nó sẽ thiết lập mã cho bạn.
Số dặm của bạn có thể thay đổi theo mã trước tiên, tôi đã không làm việc với điều đó.
Vấn đề với rất nhiều giải pháp khác, là trong khi chúng có thể hoạt động ban đầu, ngay khi bạn xây dựng lại mô hình, nó sẽ loại bỏ bất kỳ mã tùy chỉnh nào bạn chèn vào tệp do máy tạo.
Phương pháp này hoạt động bằng cách thêm một thuộc tính bổ sung vào tệp edmx:
<EntityType Name="Thingy">
<Property Name="Iteration" Type="Int32" Nullable="false" **DefaultValue="1"** />
Và bằng cách thêm mã cần thiết vào hàm tạo:
public Thingy()
{
this.Iteration = 1;
Đặt giá trị mặc định cho cột trong bảng trong Máy chủ MSSQL và trong thuộc tính thêm mã lớp, như sau:
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
cho cùng một tài sản.
this.Active = true;
? Tôi nghĩ rằng giá trị DB sẽ được ưu tiên khi tìm nạp, nhưng cẩn thận nếu mới sau đó đính kèm một thực thể để cập nhật mà không tìm nạp trước, vì theo dõi thay đổi có thể thấy điều này khi bạn muốn cập nhật giá trị. Nhận xét vì tôi đã không sử dụng EF trong một thời gian dài và tôi cảm thấy như đây là một phát súng trong bóng tối.