为什么使用T4修改EF中的实体?

问题描述 投票:1回答:5

在EF中使用'ADO.NET EntityObject Generator'的正当理由是什么?如果您不知道,它会生成一个T4文件,用于从edmx构建实体。然后,您可以更改T4文件以更改实体的生成方式。

我的问题是:除了更改实体派生的基类(也实现接口)和更改实体和/或上下文对象和命名约定的可访问性之外,这有什么用处?考虑EF和部分类的现有特征。

我想出了2

  1. 从数据库中获取表/列描述,并在实体和属性上填充摘要
  2. 生成轻型DTO,并进行自动映射。

1看起来似乎太多工作,因为它只更新模型上的评论,而不是edmx本身(虽然它可以这样做)

2这甚至有用吗?

entity-framework entity-framework-4 t4
5个回答
4
投票

我们用T4模板做了一些事情。第一个是将生成的代码拆分为每个文件一个类,而不是一个大型文件。这样可以更轻松地浏览和浏览实体。

第二个也是更重要的一个是自动生成数据注释验证属性,如StringLength和Required。这允许我们通过单个函数调用验证我们的实体,并确保它们的验证属性始终与数据库同步(因为如果我们更改DB中的列长度,例如,生成的StringLength()属性则当我们“从数据库更新模型”时更新。

在前面的工作中,我们还为实体添加了基类和接口,正如您在问题中提到的那样。


这是我们的T4模板的一个片段,它检查所需的列和字符串长度,并添加必要的验证属性:

    ''' <summary>
    ''' <#=SummaryComment(primitiveProperty)#>
    ''' </summary><#=LongDescriptionCommentElement(primitiveProperty, 1)#>
    <EdmScalarPropertyAttribute(EntityKeyProperty:=<#=code.CreateLiteral(ef.IsKey(primitiveProperty))#>, IsNullable:=<#=code.CreateLiteral(ef.IsNullable(primitiveProperty))#>)>
    <DataMemberAttribute()>
<#+
  ' begin required attribute
  If Not ef.IsNullable(primitiveProperty) and not ef.IsKey(primitiveProperty) then
#>
<#+
    If ef.ClrType(primitiveProperty.TypeUsage) = GetType(Guid) Then
#>
    <GuidRequiredAttribute(ErrorMessage:="<#=FixName(code.Escape(primitiveProperty))#> is required")>
<#+
    Else
#>
    <RequiredAttribute(ErrorMessage:="<#=FixName(code.Escape(primitiveProperty))#> is required")>
<#+
    End If
#>
<#+
  End If
    If HasMaxLength(primitiveProperty.TypeUsage) then
    Dim d = MaxLength(primitiveProperty.TypeUsage)
#>
    <StringLengthAttribute(<#=d#>, ErrorMessage:="<#=FixName(code.Escape(primitiveProperty))#> cannot be longer than <#=d#> characters")>
<#+
    End If
#>

1
投票

嗯,原因是你可以用它做任何事情。那么,为什么没有呢?当然,T4的使用非常局限于某些特殊情况,并且大多数情况下使用它没有意义。另一方面,你可以用它做一些时髦的东西。例如,您可以定义一些用户定义的东西。假设你的桌子上有一个Sort列。然后,您可以定义一个查询函数,如果此列存在,它将自动对每个条目进行排序。对于一个例子来说可能太微不足道了,但是有很多其他奇怪的架构让它更有意义。

你也可以使用其他代码生成的东西,没有EF。所以它肯定在这里是完整性和可扩展性。


1
投票

T4模板替换EFv1中使用的自定义工具以生成文件后面的代码(包含所有类的.designer.cs文件)。 T4的主要优点是你可以通过修改文本.tt文件来改变每个项目。在自定义工具的情况下,更改几乎是不可能的

使用T4,您可以完全控制从EDMX生成的实体类。它是将EDMX转换为C#或VB.NET文件。默认模板创建具有大多数开发人员所需功能的类文件,但如果您还需要其他任何内容,只需转到.tt文件并添加即可。

更改的可能性是无限的,因为EDMX文件本身是可扩展的。在EDMX背后只是XML文件,你可以在这个文件中包含你自己的自定义XML元素(它有一些限制,但它有可能 - 在模型第一种方法中,here是SQL生成的一些例子)。在EDMX中拥有自定义元素后,您可以在T4模板中将它们用作您希望包含在生成代码中的其他功能的决策逻辑。实体设计器也是可扩展的 - 您可以创建自定义扩展,这些扩展将作为自定义元素存储在EDMX文件中。 EDMX和实体设计器扩展都在书Entity Framework in Action中得到很好的描述。


1
投票

我知道这是一个古老的问题,但我很想在我开始时遇到这些信息。在我们的多层解决方案中有win32 Delphi客户端的情况下,我使用模板(在C#中)生成.Net中的DTO类和win32对应项。 这允许我们使用很大程度上自动生成的Delphi代码将CRUD功能封装在客户端上:

procedure Delete;
class function DeleteDto(const _dESPATCHID: integer)  : boolean;
class function GetNextID  : integer;
class function Get(const _dESPATCHID: integer) : TDtoDESPATCH; overload;    
class function Collection(const __filterXml: string): TList<TDtoDESPATCH>;
function Load: boolean; overload;
function Populate(_primaryDict : TDictionary<string, Variant>) : boolean;
function Save : boolean; overload;

来自客户端的更改跟踪也可以自动进行,因此每个属性设置器都将标记已更改的属性,以确保仅更新已更改的属性。例如:

procedure TDtoDESPATCH.SetSCT_STATUS(const value : string);
begin
    if (self.IsLoaded) and (inherited SCT_STATUS <> value) then
      begin
        TrackChange('SCT_STATUS');
        self.Modified:= True;
      end;
    inherited SCT_STATUS := value;
end;

在服务器端,另一个模板负责自动生成的WCF服务中的所有CRUD操作,该服务也作为asmx Web服务公开。接口,WCF方法和所有注释都是从模板生成的。

// convert to entity
var _entity = _dto.ToEntity();
if(exists)
{
    Global.LogActivity(string.Format("{0} - profile {1}, updating DESPATCH: {2}", racID, profile, _dto.ChangedProperties ));
    // Attach the entity to the db
    db.DESPATCHes.Attach(_entity);
    // Change tracking
    ChangeTracking<DESPATCH>(_dto.ModifiedProperties, db, _entity);
}

在WIN32必须成为解决方案的一部分的情况下,手动编码所有这些将是(更糟糕的)噩梦。


0
投票

我已经使用它们来生成对Datalayer级别有用的代码。

改变是否实现其他合同(接口),添加方法,注释以及非分层应用程序(除此之外不建议)添加属性更改通知。

通过在Datalayer中添加一些这些项目,我已经能够在Model项目中使用模板来生成此级别的锅炉板代码。

最重要的是,如果您可以安全地让计算机为您编码,那么它非常值得。在我们的例子中,80%的基本管道工作可以是代码生成的 - 如果它不正确,通常很容易修复和重新生成。

© www.soinside.com 2019 - 2024. All rights reserved.