【问题标题】:How to set default value for POCO's in EF CF?如何在 EF CF 中设置 POCO 的默认值?
【发布时间】:2011-03-09 10:34:32
【问题描述】:

在 Entity Framework Code First 方法中,如何为 POCO 的 EntityConfiguration 类中的属性设置默认值?

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime CreatedOn { get; set; }
}

public class PersonConfiguration : EntityConfiguration<Person>
{
    public PersonConfiguration()
    {
        Property(p => p.Id).IsIdentity();
        Property(p => p.Name).HasMaxLength(100);

        //set default value for CreatedOn ?
    }
}

【问题讨论】:

  • 万一有人想知道。我最终使用“存储库模式”(stackoverflow.com/questions/3175/…),在插入期间设置默认值。这是一个很好的分离,因为我正在考虑在未来离开 EF。
  • +1 表示“将来远离 EF”。浪费了很多时间,我本来可以为我当前的应用程序编写 SQL 代码!但是你打算用什么? NHibernate,是不是更好?

标签: .net entity-framework ef-code-first entity-framework-4


【解决方案1】:

随着 Entity Framework 4.3 的发布,您可以通过迁移来做到这一点。

EF 4.3 Code First Migrations Walkthrough

所以使用你的例子它会是这样的:

public partial class AddPersonClass : DbMigration
{
    public override void Up()
    {
        CreateTable(
            "People",
            c => new
                {
                    Id = c.Int(nullable: false, identity: true),
                    Name = c.String(maxLength: 100),
                    CreatedOn = c.DateTime(nullable: false, defaultValue: DateTime.UtcNow)
                })
            .PrimaryKey(t => t.Id);
    }

    public overide void Down()
    {
        // Commands for when Migration is brought down
    }
}

【讨论】:

  • 您可以使用AlterColumn 成功修改默认值而不删除和重新创建列或表吗?
  • 有没有办法通过扩展EntityTypeConfiguration来做到这一点?例如,任何带有 Guid 的东西总是默认为 newsequentialid()?
【解决方案2】:

您可以通过类的构造函数设置默认值。这是我当前项目中的一个类,使用 MVC3 和 Entity Framework 4.1:

namespace MyProj.Models
{
using System;
using System.Collections.Generic;

public partial class Task
{
    public Task()
    {
        this.HoursEstimated = 0;
        this.HoursUsed = 0;
        this.Status = "To Start";
    }

    public int ID { get; set; }
    public string Description { get; set; }
    public int AssignedUserID { get; set; }
    public int JobID { get; set; }
    public Nullable<decimal> HoursEstimated { get; set; }
    public Nullable<decimal> HoursUsed { get; set; }
    public Nullable<System.DateTime> DateStart { get; set; }
    public Nullable<System.DateTime> DateDue { get; set; }
    public string Status { get; set; }

    public virtual Job Job { get; set; }
    public virtual User AssignedUser { get; set; }
}
}

【讨论】:

  • 如果HoursUsed 的数据库存储值为5.0 会怎样?构造函数会覆盖数据库值吗?还是会先构造,然后用实际值替换默认的0?
【解决方案3】:

我知道这个话题已经持续了一段时间,我也遇到了同样的问题。到目前为止,我还没有找到一种解决方案,可以将整个东西放在一个地方,这样代码仍然可读。

在创建用户时,我希望对象本身通过private setters 设置一些字段,例如GUID 和创建日期,而不是“污染”构造函数。

我的用户类:

public class User
{
    public static User Create(Action<User> init)
    {
        var user = new User();
        user.Guid = Guid.NewGuid();
        user.Since = DateTime.Now;
        init(user);
        return user;
    }

    public int UserID { get; set; }

    public virtual ICollection<Role> Roles { get; set; }
    public virtual ICollection<Widget> Widgets { get; set; }

    [StringLength(50), Required]
    public string Name { get; set; }
    [EmailAddress, Required]
    public string Email { get; set; }
    [StringLength(255), Required]
    public string Password { get; set; }
    [StringLength(16), Required]
    public string Salt { get; set; }

    public DateTime Since { get; private set; }
    public Guid Guid { get; private set; }
}

调用代码:

context.Users.Add(User.Create(c=>
{
    c.Name = "Name";
    c.Email = "some@one.com";
    c.Salt = salt;
    c.Password = "mypass";
    c.Roles = new List<Role> { adminRole, userRole };
}));

【讨论】:

    【解决方案4】:

    【讨论】:

    • 代码优先仍然是 CTP。如果您还没有,请为此写一份连接报告。
    • 实际上我认为这是一个积极的设计决策。在数据库中设置默认值是除了代码方法之外的一种步骤。
    • 好吧,我确实希望“仅代码”意味着一切都在代码中配置。在数据库中手动设置默认值不是一个好主意,因为我需要实体框架使用 context.CreateDatabase() 函数为我创建数据库,而且我真的不想同时维护代码和数据库脚本同时。
    • 您可以将默认值视为您的 Person 类的一部分。当您在数据库中设置默认值时,您将遇到以下问题:在您保存实体之前,这些属性不会被初始化。当您生成 POCO 时,这是 DB First 和 Model First 中的问题。
    • 您认为在上下文中使用 SavingChanges 时添加默认值是个好主意吗?
    【解决方案5】:

    我不确定从哪个版本的 EF 开始可用,但从版本 5 开始,您肯定可以处理这个问题。只需在 SQL 中的列上设置 GetDate() 的默认值,在 TSQL 或设计器中,然后设置您的 EF 类,如下所示:

    public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public DateTime CreatedOn { get; set; }
    }
    
    public class PersonConfiguration : EntityConfiguration<Person>
    {
        public PersonConfiguration()
        {
            Property(p => p.Id).IsIdentity();
            Property(p => p.Name).HasMaxLength(100);
    
            this.Property(p => p.CreatedOn ).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Computed);
        }
    }
    

    请注意,您不需要将数据库列或 POCO 属性设为可为空。

    【讨论】:

    • 我认为重点是在使用 Code First 时让 EF 设置默认值,而不必进入 SQL 并自己设置。
    【解决方案6】:

    如果您希望 SQL Server 以实现此目的的方式提供默认日期,重要的部分是 defaultValueSql: "GETDATE()" 它将设置 sql server 默认值,而不仅仅是计算时间脚本已运行(即 DateTime.UtcNow)

       public partial class AddPersonClass : DbMigration
        {
        public override void Up()
        {
            CreateTable(
                "People",
                c => new
                    {
                        Id = c.Int(nullable: false, identity: true),
                        Name = c.String(maxLength: 100),
                        CreatedOn = c.DateTime(nullable: false, defaultValueSql: "GETDATE()")
                    })
                .PrimaryKey(t => t.Id);
        }
    
        public overide void Down()
        {
            // Commands for when Migration is brought down
        }
    }
    

    【讨论】:

      【解决方案7】:

      除了使用 DB MIGRATIONS 并启用迁移之外别无他法,您必须像这样设置属性

      [DatabaseGenerated(DatabaseGeneratedOption.Computed)]        
          public DateTime CreatedOn { get; set; }
      

      创建数据库后,您必须按照以下步骤启用迁移。 转到程序管理器控制台并逐个执行以下命令

      • PM&gt; Enable-Migrations
      • PM&gt; Add-Migration AlterMyTable 这里的 AlterMyTable 可以是任何名称。 这将在您的解决方案currentTimestamp_AlterMyTable.cs 中新添加的 Migrations 文件夹下创建一个文件 - 现在将以下内容复制到 currentTimestamp_AlterMyTable.cs 的 Up 方法中
      • AlterColumn("Person", "CreatedOn", n =&gt; n.DateTime(nullable: false, defaultValueSql: "SYSUTCDATETIME()")); 然后在程序管理器控制台中执行最后一个命令
      • PM&gt; Update-Database 现在,如果您在数据库中看到Person 表,然后导航到CreatedOn 列,它的默认值应该是SYSUTCDATETIME(),即现在如果您尝试向该表中插入一些数据,您的数据库将自动更新本专栏 CreatedOn 为您推荐。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-07-17
        • 1970-01-01
        • 1970-01-01
        • 2021-12-14
        • 2011-12-31
        • 2010-11-14
        • 2021-09-22
        • 2020-01-18
        相关资源
        最近更新 更多