16

私は最初にEF 4データベース+ POCOを使用しています。受信する DateTime が UTC の種類であることを EF に簡単に示す方法がないため、プロパティを自動生成ファイルから別のファイルの部分クラスに移動しました。

    private DateTime _createdOn;
    public virtual System.DateTime CreatedOn
    {
        get { return _createdOn; }
        set
        {
            _createdOn =
                (value.Kind == DateTimeKind.Unspecified)
                    ? _createdOn = DateTime.SpecifyKind(value, DateTimeKind.Utc)
                    : value;
        }
    }

ただし、モデルを更新するたびに、自動化されたプロパティが T4 世代で再度作成されます。もちろん、これにより次のコンパイル エラーが発生します。「型 'Foo' には、'CreatedOn' の定義が既に含まれています。

そのプロパティを生成せず、自分で処理できるように EF に指示する方法はありますか?

アップデート

みんなの答えをありがとう...

別の名前で新しいカスタム プロパティを作成しました。

    public virtual System.DateTime CreatedOnUtc
    {
        get
        {
            return (CreatedOn.Kind==DateTimeKind.Unspecified)
                ? DateTime.SpecifyKind(CreatedOn, DateTimeKind.Utc)
                : CreatedOn;
        }
        set
        {
            CreatedOn =
                (value.Kind == DateTimeKind.Unspecified)
                    ? CreatedOn = DateTime.SpecifyKind(value, DateTimeKind.Utc)
                    : value;
        }
    }

また、Linq-to-Entities クエリで使用する必要のあるプロパティを除いて、自動生成されたプロパティのすべてのセッターとゲッターを Private に設定しました (ため息)。そのような場合、それらのゲッターを internal に設定します。

EFがそれを扱うべきDateTimeの「種類」を指定するDateTime型のドロップダウンがあればいいのにと思います。それは時間と余分な複雑さを節約したでしょう.

4

6 に答える 6

24

別のアプローチは、DbContext の ObjectMaterialized イベントにフックし、そこで種類を設定することです。

私の DbContext コンストラクターでは、次のようにします。

    ((IObjectContextAdapter)this).ObjectContext.ObjectMaterialized += new ObjectMaterializedEventHandler(ObjectMaterialized);

メソッドは次のようになります。

private void ObjectMaterialized(object sender, ObjectMaterializedEventArgs e)
        {
            Person person = e.Entity as Person;
            if (person != null) // the entity retrieved was a Person
            {
                if (person.BirthDate.HasValue)
                {
                    person.BirthDate = DateTime.SpecifyKind(person.BirthDate.Value, DateTimeKind.Utc);
                }
                person.LastUpdatedDate = DateTime.SpecifyKind(person.LastUpdatedDate, DateTimeKind.Utc);
                person.EnteredDate = DateTime.SpecifyKind(person.EnteredDate, DateTimeKind.Utc);
            }
        }

欠点は、関心のある各プロパティに対して必ず設定する必要があることですが、少なくとも可能な限り低いレベルで設定されます。

于 2012-02-21T22:32:05.760 に答える
15

私は Michael と同じアプローチを使用した後、もう少し深く掘り下げ、リフレクションを使用して DateTime と DateTime を検索しましたか?

すべての DateTime 値が Utc DateTimes として読み取られるようにするための私のソリューションは次のとおりです。

最初に、DbContext Extensions メソッド クラスにある 3 つのメソッドを作成しました。複数の DbContext に使用する必要があるため

public static void ReadAllDateTimeValuesAsUtc(this DbContext context)
{
        ((IObjectContextAdapter)context).ObjectContext.ObjectMaterialized += ReadAllDateTimeValuesAsUtc;
}

private static void ReadAllDateTimeValuesAsUtc(object sender, ObjectMaterializedEventArgs e)
{
    //Extract all DateTime properties of the object type
    var properties = e.Entity.GetType().GetProperties()
        .Where(property => property.PropertyType == typeof (DateTime) ||
                           property.PropertyType == typeof (DateTime?)).ToList();
    //Set all DaetTimeKinds to Utc
    properties.ForEach(property => SpecifyUtcKind(property, e.Entity));
}

private static void SpecifyUtcKind(PropertyInfo property, object value)
{
    //Get the datetime value
    var datetime = property.GetValue(value, null);

    //set DateTimeKind to Utc
    if (property.PropertyType == typeof(DateTime))
    {
        datetime = DateTime.SpecifyKind((DateTime) datetime, DateTimeKind.Utc);
    }
    else if(property.PropertyType == typeof(DateTime?))
    {
        var nullable = (DateTime?) datetime;
        if(!nullable.HasValue) return;
        datetime = (DateTime?)DateTime.SpecifyKind(nullable.Value, DateTimeKind.Utc);
    }
    else
    {
        return;
    }

    //And set the Utc DateTime value
    property.SetValue(value, datetime, null);
}

次に、DbContext オブジェクトである WebsiteReadModelContext のコンストラクターに移動し、ReadAllDateTimeValuesAsUtc メソッドを呼び出します。

public WebsiteReadModelContext()
{
      this.ReadAllDateTimeValuesAsUtc();
}
于 2012-07-27T07:05:31.150 に答える
6

edmx を使用して、CreatedOn プロパティに別の名前 (CreatedOnInternal など) を指定します。次に、生成のアクセス修飾子を Public ではなく Internal に設定します。その後、カスタム プロパティを部分クラスに実装でき、これについて心配する必要はありません。

于 2011-08-03T18:04:49.947 に答える
4

EF で生成されたクラスを手動で変更しようとすると、面倒なことになると思います。

追求することをお勧めする 2 つのオプションがあります。

  1. 既存のプロパティを変更しないで、新しいプロパティを部分クラスに追加するCreatedOnUTCか、同様のものを追加します。
  2. T4 テンプレートを変更して、これらの日付プロパティのアクセサーを生成する方法を変更します (すべての DateTime プロパティが同じように機能すると、より簡単になります)。型に依存するため、簡単ではありませんが、少なくとも将来ジェネレーターを使用できるようになります。
于 2011-08-03T18:05:31.650 に答える
4

EF は、それが生成するものに関しては、かなり厄介な場合があります。
Database First アプリケーションで同様の問題が発生した場合、通常は次のアプローチに従います。

  • 自動生成されたプロパティを残しますが、それらを作成しprivateて名前を変更します。
  • ビジネス コードに適した公開の「ラッピング」プロパティを追加します。

たとえば、(credits to Jeff )CreatedOnのような別の名前に変更し、デザイナーで非公開としてマークします。部分クラスでは、変換を行ったり来たりするパブリックラッパー プロパティを追加します。CreatedOnInternal CreatedOn

于 2011-08-03T18:11:24.727 に答える