7

Entity Framework 4.1を使い始めたばかりで、「データベースファースト」モードを試しています。EFが「ADO.NetDbContextGenerator」を使用してモデルクラスを生成する場合、[Key]属性を使用してクラスの主キーを識別すべきではありませんか?これがないと、T4MVCScaffoldingと互換性がないように見えます。

詳細は次のとおりです。

Entity Data Model Designer GUIを使用して、既存のデータベースからモデルに単純な「国」テーブルを追加しました。GUIは、「PK」という名前の単一の整数IDキーフィールドを主キーとして正しく識別します。(残念ながら、私は新しいユーザーなので、スクリーンショットを追加できません。代わりにCSDLを以下に含めました。)ただし、EFが「ADO.NetDbContext Generator」を使用してコードを生成する場合、PKは識別されません。生成されたクラスのキーフィールドとしてのフィールド(以下のコードの抜粋を参照)。

「国」テーブルのCSDL:

<edmx:ConceptualModels>
  <Schema Namespace="EpiDataModel" Alias="Self" xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation" xmlns="http://schemas.microsoft.com/ado/2008/09/edm">
    <EntityContainer Name="EpiModelEntities" annotation:LazyLoadingEnabled="true">
      <EntitySet Name="countries" EntityType="EpiDataModel.country" />
    </EntityContainer>
    <EntityType Name="country">
      <Key>
        <PropertyRef Name="PK" />
      </Key>
      <Property Name="PK" Type="Int32" Nullable="false" annotation:StoreGeneratedPattern="Identity" />
      <Property Name="Abbreviation" Type="String" Nullable="false" MaxLength="200" Unicode="false" FixedLength="false" />
      <Property Name="Name" Type="String" MaxLength="1024" Unicode="false" FixedLength="false" />
      <Property Name="Description" Type="String" MaxLength="1024" Unicode="false" FixedLength="false" />
      <Property Name="Sequence" Type="Int32" />
    </EntityType>
  </Schema>
</edmx:ConceptualModels>

自動生成されたコードは次のとおりです。

//------------------------------------------------------------------------------
// <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>
//------------------------------------------------------------------------------

using System;
using System.Collections.Generic;

namespace MvcApplication1.Areas.Epi.Models
{
    public partial class country
    {
        public int PK { get; set; }
        public string Abbreviation { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        public Nullable<int> Sequence { get; set; }
    }
}

これにより、MVCScaffoldingT4テンプレートを使用してコントローラーをスキャフォールディングしようとすると問題が発生します。「主キーのように見えるプロパティはありません」というエラーが表示されます。NuGetパッケージマネージャーコンソールからのコマンドと出力は次のとおりです。

PM> scaffold controller MvcApplication1.Areas.Epi.Models.country -Area Epi -NoChildItems -DbContextType MvcApplication1.Areas.Epi.Models.EpiModelEntities -Force
Scaffolding countriesController...
Get-PrimaryKey : Cannot find primary key property for type 'MvcApplication1.Areas.Epi.Models.country'. No properties appear to be primary keys.
At C:\work\EPI\EPIC_MVC3\sandbox\MvcApplication1\packages\MvcScaffolding.1.0.6\tools\Controller\MvcScaffolding.Controller.ps1:74 char:29
+ $primaryKey = Get-PrimaryKey <<<<  $foundModelType.FullName -Project $Project -ErrorIfNotFound
    + CategoryInfo          : NotSpecified: (:) [Get-PrimaryKey], Exception
    + FullyQualifiedErrorId : T4Scaffolding.Cmdlets.GetPrimaryKeyCmdlet

ただし、生成されたクラスを手動で変更して[Key]属性をフィールドに追加すると、上記とまったく同じスキャフォールディングコマンドが正常に機能します。

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; // manually added

namespace MvcApplication1.Areas.Epi.Models
{
    public partial class country
    {
        [Key]                        // manually added
        public int PK { get; set; }
        public string Abbreviation { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        public Nullable<int> Sequence { get; set; }
    }
}

では、なぜEFDatabaseFirstとT4MVCScaffoldingが一緒にうまく機能しないのでしょうか。そして、足場の問題がなくても、EFクラスはキーフィールドが何であるかを知る必要はありませんか?

4

2 に答える 2

5

T4テンプレートは、テンプレートから生成されたクラスがデータ注釈を必要としないため、データ注釈を使用しません。マッピングはコードではなくXMLファイルで定義されているため、EFもそれらを必要としません。データ注釈が必要な場合は、次のいずれかを行う必要があります。

  • それらを使用するようにT4テンプレートを変更します(これにはEFメタデータモデルの理解が必要です)
  • テンプレートを使用せず、代わりに最初にコードを使用してください
  • バディクラスを使用してデータアノテーションを手動で追加し、scaffoldがそれらを認識することを期待します
于 2011-12-07T22:55:39.133 に答える
2

誰かがこれをしたい場合は、 james mannings githubでいくつかの興味深いテンプレートを見つけました。 これらのテンプレートにはより多くの機能がありますが、これらから引き出したビットは次のとおりです
。1)Entity.ttの上部にある使用法を次のように置き換えます。

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
<#
    if (efHost.EntityFrameworkVersion >= new Version(4, 4))
    {
       WriteLine("using System.ComponentModel.DataAnnotations.Schema;");
    }
#>

2)次に、この行を見つけます(プロパティを出力します)

    <#= Accessibility.ForProperty(property) #> <#= typeUsage #> <#= code.Escape(property) #> { get; set; }

3)このテンプレートコードを追加します

    var attributes = new List<string>();
    var isPartOfPrimaryKey = efHost.EntityType.KeyMembers.Contains(property);
    var primaryKeyHasMultipleColumns = efHost.EntityType.KeyMembers.Count > 1;

    if (isPartOfPrimaryKey)
    {
        if (primaryKeyHasMultipleColumns)
        {
            var columnNumber = efHost.EntityType.KeyMembers.IndexOf(property);
            attributes.Add(String.Format("[Key, Column(Order = {0})]", columnNumber));
        }
        else
        {
            attributes.Add("[Key]");
        }
    }
    PushIndent(new string(' ', 8));
    foreach (var attribute in attributes)
    {
        WriteLine(attribute);
    }
    ClearIndent();
于 2013-12-20T02:05:35.643 に答える