Entity Framework 4 POCO 中的默认 SQL Server 列值

发布于 2024-11-16 07:05:06 字数 857 浏览 0 评论 0原文

我已从包含默认列值的现有数据库生成了 EDMX。我还有使用 T4 模板生成的 POCO 对象。

现在我有一个场景,我想创建一个 POCO 并将其保存到数据库,如下所示:

dim tablePocoEntityInstance as New tablePocoEntity
context.MsSQLTable.AddObject(tablePocoEntityInstance)
context.SaveChanges()

除了 SQL Server 数据库中设置的默认值之外,这工作正常。

例如:

SQL Server 表

  id (int, not null, auto increament)
  magicNR (int, not null, defaultValue = 11)

生成的 POCO 对象有两个属性:

Partial Public Class tablePocoEntity
    Public Overridable Property id As Integer
    Public Overridable Property magicNR As Integer
...

问题是 magicNR 不可为空并且会被隐式初始化。当我保存对象时,id 应该是这样,但 magicNR 的值为 0,而不是默认值 11。

我的问题:

  1. 我可以以使用数据库默认列值的方式设置我的实体吗?
  2. 如果不是,我如何在代码中设置默认值?
  3. 处理这个问题的最佳方法是什么?

I have generated my EDMX from an existing database which contains default column values. I have also POCO object generated with T4 template.

Now I have a scenario where I want to create a POCO and save it to the database like this:

dim tablePocoEntityInstance as New tablePocoEntity
context.MsSQLTable.AddObject(tablePocoEntityInstance)
context.SaveChanges()

This is working fine with exception of default values that are set in the SQL Server database.

For example:

SQL Server Table

  id (int, not null, auto increament)
  magicNR (int, not null, defaultValue = 11)

Generated POCO object has then two properties:

Partial Public Class tablePocoEntity
    Public Overridable Property id As Integer
    Public Overridable Property magicNR As Integer
...

Problem is that magicNR is not nullable and get implicitly initialized. When I save the object, id is as it should be but magicNR has value 0 and not 11 which is the default value.

My questions:

  1. Can I set up my entities in a way that they will use database default column values?
  2. If not how can I set the default values in the code?
  3. What is the best way to deal with this problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

只想待在家 2024-11-23 07:05:06

打开您的实体 .edmx 并右键单击相关数据字段并选择属性。在 DataBaseScriptGeneration 下,将 StoreGeneratePattern 更改为“已计算”。设置完成后,您的应用程序将按预期工作 - SQL Server 会插入默认值。但是,您将无法从应用程序端强制输入值。

Open up your entity .edmx and right click on the data field in question and select properties. Under DataBaseScriptGeneration, change StoreGeneratedPattern to "Computed". Once that it set, your app will work as expected - where SQL Server inserts the default value. However, you will then not be able to force a value from the app side.

小情绪 2024-11-23 07:05:06

我知道没有开箱即用的解决方案 - 但由于这些 POCO 类是使用 T4 模板从数据库生成的,因此您始终可以修改这些模板来检查数据库并查找和遵守列默认值。

在这种情况下,您的对象可能有一个构造函数,它将这些列设置为数据库定义定义的默认值。

There is no out-of-the-box solution that I'd be aware of - but since those POCO classes are generated from the database using T4 templates, you could always modify those templates to inspect the database and find and honor column defaults.

In that case, your object then might have a constructor that would set those columns to the default values that the database definition defines.

倾城°AllureLove 2024-11-23 07:05:06

好吧,这个问题已经很老了,但我仍然想分享我的解决方案。

我所做的是修改 T4 模板,以便向所有生成的实体添加部分方法并从构造函数中调用它。
此分部方法是在扩展分部类中实现的,您将为需要设置默认值的每个实体手动创建该分部类。

注意:我使用的是 EF6

简短步骤:

1) 修改 T4 模板以包含如下所示的分部方法:

partial void OnCreationComplete();

2) 修改 T4 模板以在构造函数中调用该方法

OnCreationComplete();

3) 为您需要的实体创建分部类设置默认属性并实现 OnCreationComplete 方法:

partial void OnCreationComplete()
{
    PropertyFoo = "Bar";
}

这是完整的代码:

T4 Template

// You might want to remove the IF statement that excludes the constructor generation for entities without collection and complex entities...
<#
    var propertiesWithDefaultValues = typeMapper.GetPropertiesWithDefaultValues(entity);
    var collectionNavigationProperties = typeMapper.GetCollectionNavigationProperties(entity);
    var complexProperties = typeMapper.GetComplexProperties(entity);
#>
    public <#=code.Escape(entity)#>()
    {
<#
        foreach (var edmProperty in propertiesWithDefaultValues)
        {
#>
        <#=code.Escape(edmProperty)#> = <#=typeMapper.CreateLiteral(edmProperty.DefaultValue)#>;
<#
        }

        foreach (var navigationProperty in collectionNavigationProperties)
        {
#>
        <#=code.Escape(navigationProperty)#> = new HashSet<<#=typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType())#>>();
<#
        }

        foreach (var complexProperty in complexProperties)
        {
#>
        <#=code.Escape(complexProperty)#> = new <#=typeMapper.GetTypeName(complexProperty.TypeUsage)#>();
<#
        }
#>
        OnCreationComplete();
    }

    partial void OnCreationComplete();

生成类的示例:

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated from a template.
//
//     Manual changes to this file may cause unexpected behavior in your application.
//     Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace MyTest.DAL
{

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;

    public partial class Foo
    {
        public Foo()
        {
            OnCreationComplete();
        }

        partial void OnCreationComplete();

        public string MyPropertyFoo { get; set; }

    }
}

扩展部分类

public partial class Foo
{
    partial void OnCreationComplete()
    {
        MyPropertyFoo = "Bar";
    }
}

希望它可以帮助某人...

Ok, this question is quite old but still I'd like to share my solution to this.

What I did is to modify the T4 template in order to add a partial method to all generated entities and to call it from the constructor.
This partial method is implemented in an extended partial class which you will manually create for each entity you need to set default values.

Note: I'm using EF6

Short steps:

1) Modify the T4 template to include a partial method like this:

partial void OnCreationComplete();

2) Modify the T4 template to invoke that method in the constructor

OnCreationComplete();

3) Create a partial class for those entities which you need to set a default property and implement the OnCreationComplete method:

partial void OnCreationComplete()
{
    PropertyFoo = "Bar";
}

Here is the complete code:

T4 Template

// You might want to remove the IF statement that excludes the constructor generation for entities without collection and complex entities...
<#
    var propertiesWithDefaultValues = typeMapper.GetPropertiesWithDefaultValues(entity);
    var collectionNavigationProperties = typeMapper.GetCollectionNavigationProperties(entity);
    var complexProperties = typeMapper.GetComplexProperties(entity);
#>
    public <#=code.Escape(entity)#>()
    {
<#
        foreach (var edmProperty in propertiesWithDefaultValues)
        {
#>
        <#=code.Escape(edmProperty)#> = <#=typeMapper.CreateLiteral(edmProperty.DefaultValue)#>;
<#
        }

        foreach (var navigationProperty in collectionNavigationProperties)
        {
#>
        <#=code.Escape(navigationProperty)#> = new HashSet<<#=typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType())#>>();
<#
        }

        foreach (var complexProperty in complexProperties)
        {
#>
        <#=code.Escape(complexProperty)#> = new <#=typeMapper.GetTypeName(complexProperty.TypeUsage)#>();
<#
        }
#>
        OnCreationComplete();
    }

    partial void OnCreationComplete();

Example of generated class:

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated from a template.
//
//     Manual changes to this file may cause unexpected behavior in your application.
//     Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace MyTest.DAL
{

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;

    public partial class Foo
    {
        public Foo()
        {
            OnCreationComplete();
        }

        partial void OnCreationComplete();

        public string MyPropertyFoo { get; set; }

    }
}

Extended partial class

public partial class Foo
{
    partial void OnCreationComplete()
    {
        MyPropertyFoo = "Bar";
    }
}

Hope it helps someone...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文