背景:我正在开始一个项目,使用Linq2Sql将Web应用程序转换为使用Entity Framework(v6)。我对L2S有很多经验,但我对EF来说是全新的。由于我们的应用程序及其数据库已经存在,我们正在使用“数据库优先”方法。此外,数据库正在不断发展,因此我们正在对模式进行更改,并从修订后的数据库更新模型,每次都会为EF模型重新生成代码。
对于我们的许多实体(数据库表),无论何时构造实体,我们都会在代码中设置默认值。在Linq2Sql中,很容易:为实体定义一个部分类,并像这样在类中添加一个方法:
partial void OnCreated() { SomeProperty = SomeDefaultValue; }
每当Linq2Sql构造一个新的实体对象时,它会调用您定义的OnCreated()方法,并根据需要设置默认值。它很棒。
问题:在EF中,我没有看到在数据库优先方案中执行此操作的方法。
如果我修改EF生成的模型代码,只要我们在数据库修订后更新模型,就会覆盖模型代码。
如果我在单独的文件中定义实体的部分类并定义构造函数,编译器会抱怨构造函数已经定义。
似乎对L2S的OnCreated()方法似乎没有任何支持。
有什么建议吗?
编辑:感谢大家的有益评论,但我想我需要指出一个重要的考虑因素:我的目标是使用数据库优先的方法并坚持下去,而不是切换到代码优先。当数据库模式随时间变化时,我希望EF Designer(或POCO Generator或任何工具)更新我的EF实体类以匹配。在应用程序中构造类时,所有这些都不会丢失我的初始化类属性。这在Linq2Sql中很容易,但我只是没有看到在EF数据库中实现这一点的方法。欢迎所有建议!答案 0 :(得分:3)
使用数据库优先方法并坚持使用它,即使数据库架构随时间发生变化也是如此。也就是说,让EF根据预先存在的数据库为每个数据库表实体生成代码,并在数据库被更改时更新代码。
提供每次构造对象时初始化实体对象属性的机制,例如Employee.Dependents = 1
。 (我知道数据库模式可以设置简单的默认值,但必须通过代码执行更复杂的初始化。)
更改数据库架构并重新生成模型代码时,必须保留自定义初始化代码。
每次在数据库优先方案中构造实体对象时,EF都不提供设置属性的方法。编辑EF生成的代码不起作用,因为只要EF在更改数据库模式后重新生成代码,它就会被覆盖。到目前为止,我想到了四种解决方法:
一个想法是为每个实体类添加一个超过默认零参数构造函数的构造函数。例如,c = new Customer(x)
而非默认c = new Customer()
。应用程序代码将调用新的构造函数,该构造函数将继承默认构造函数并添加其他代码以初始化类属性。这避免了重复默认构造函数,这是C#不允许的。新构造函数位于单独的部分类文件中,因此当EF从数据库生成更新的模型时,它不会被覆盖。
但是,应用程序员可能会意外调用默认构造函数,从而导致细微的错误。
另一个解决方案是将实体类包装在另一个类中,例如,Customer2
类围绕Customer
类。新类将继承原始类,并根据需要为任何属性添加初始化代码。
由于这些新类与原始实体类代码是分开的,因此在重新生成模型代码时,它们不会被EF覆盖。可以从顶级应用程序代码中隐藏实体类,以避免意外地意外引用原始类。如果是这样,这应该是一个很好的技术,虽然我还没有测试过。
第三方工具 EntityFramework Reverse POCO Generator 是一个帮助。它像EF一样生成POCO模型代码,但不是 EF。它有一个生成部分类的选项,实体类包含一个InitializePartial()
方法,就像Linq2Sql的OnCreated()
一样。我认为这可以很好地重新生成代码,因为数据库会随着时间的推移而改变。我担心的是,这是第三方产品,而且它总是存在过时或不受支持的风险。
最后,您可以更改EF用于生成代码的模板。基本思想是让生成的代码为每个类添加“partial void OnCreated()
”,这样我们就可以使用Linq2Sql中内置的相同方便技术。我假设较新版本的EF可能会覆盖模板更改,但它只是模板中的一个更改,而不是对每个实体类的更改。此处描述了此方法(How to efficiently set default entity values in Entity Framework 6, Database First),YouTube视频在此处(https://www.youtube.com/watch?v=i8J2ipImMuU)。
感谢所有贡献者!我希望这个页面对其他人有帮助,所以你不必像寻找解决方案那样花费太多时间。
答案 1 :(得分:3)
1。打开 .edmx 文件
2。选择具有默认值的字段,然后选择转到属性
3。然后选择 StoreGeneratedPattern
4。然后将值更改为计算
我认为它有效。
答案 2 :(得分:1)
使用EF反向poco模板 - 它将从数据库中获取默认值。您可以覆盖分部类中的InitializePartial方法,以在代码中设置默认值。
答案 3 :(得分:0)
来自EF背景,我通常在代码中手动执行第一次迁移。在生成的迁移的up函数中,您可以执行类似这样的操作
<h1>@this.ViewData["hi"]</h1>
或者要添加默认SQL值,请使用
AddColumn("dbo.Person", "IsActive", c => c.Boolean(nullable: false, defaultValue: true));
AddColumn("dbo.Person", "Name", c => c.String(nullable: false, defaultValue: "Mirza"));
然而,在我看来,这种方法的缺点是你必须跟踪你的(无用的)迁移。
答案 4 :(得分:0)
刚刚发现这篇文章寻找同一问题的答案。这是一个适合我的工作。
为要为其指定默认值的实体(数据库表)创建一个分部类,例如:
namespace myApplication.MyModel
{
public partial class myEntityName
{
public myEntityName(bool InitialiseOnConstruct) : this()
{
if (InitialiseOnConstruct)
{
this.property1 = defaultValue1;
this.property2 = defaultValue1;
}
}
}
}
然后在代码中构建实体:
thisEntity = new EntityName(true);
好的,这是一个额外的步骤,但它有效。希望有所帮助。