3

Entity Framework 5モデルで列挙型を定義しました。これは、テーブルのフィールドのタイプを定義するために使用しています。

public enum PrivacyLevel : byte {
  Public = 1,
  FriendsOnly = 2,
  Private = 3,
}

そして、ここで説明する方法を使用して、上記で定義したタイプを使用するためにEFモデルにマップしたフィールドPublicationを持つテーブルがあります。tinyintPrivacyLevelPrivacyLevel

ただし、列挙型の値ごとに文字列の説明を表示できるようにもしたいと思います。これは、過去に列挙型に対してDescription属性で装飾することによって行ったものです。

public enum PrivacyLevel : byte {
  [Description("Visible to everyone")]
  Public = 1,
  [Description("Only friends can view")]
  FriendsOnly = 2,
  [Description("Only I can view")]
  Private = 3,
}

列挙型がDescription属性を持っているかどうかをチェックすることで列挙型を文字列に変換するコードがあり、それはうまく機能します。しかし、ここでは、モデルで列挙型を定義する必要があったため、基になるコードは自動生成され、それらを装飾するための安定した場所がありません。

回避策のアイデアはありますか?

4

3 に答える 3

14

これがあなたが求めているものかどうかはわかりませんが、私が理解していることから、具体的なデータベースの最初のアプローチがあるので、AutoMapperを介したDtoアプローチを使用してエンティティモデルの多くをViewModelに抽象化できます。

オートマッパープロファイルを使用すると、柔軟性と適応性のために、あらゆる種類の環境とシナリオのプロファイルをすばやく設定できます。

だからここに私に問題を引き起こしているこの「列挙型」があります

これがこの列挙型のビューモデルです

まずここに私のレイアウトがあります

これは、アカウントエンティティのアカウントのビューモデルへの単純なマッピングです。

public class AccountProfile : Profile
{
    protected override void Configure()
    {
        // Map from Entity object to a View Model we need or use
        // AutoMapper will automatically map any names that match it's conventions, ie properties from Entity to ViewModel have exact same name properties

        Mapper.CreateMap<Account, AccountViewModel>()
              .ForMember(model => model.CurrentPrivacy, opt => opt.MapFrom(account => (PrivacyLevelViewModel)account.PrivacyLevel));

        Mapper.CreateMap<Account, EditAccountViewModel>()
            .ForMember(model => model.SelectedPrivacyLevel, opt => opt.MapFrom(account => (PrivacyLevelViewModel) account.PrivacyLevel));

        // From our View Model Changes back to our entity

        Mapper.CreateMap<EditAccountViewModel, Account>()
              .ForMember(entity => entity.Id, opt => opt.Ignore()) // We dont change id's
              .ForMember(entity => entity.PrivacyLevel, opt => opt.MapFrom(viewModel => (PrivacyLevel)viewModel.NewSelectedPrivacyLevel));

    }


}

これはMVCに適用する必要はなく、WPFやWebに関連付けられていない他のアプリケーションで使用できることに注意してください。ただし、これは説明に適しているため、この例ではMVCを使用しました。

プロファイルのHttpGetリクエストを最初に受け取ったとき、データベースからエンティティを取得し、実際に必要なものをすべてビューにマップします

public ActionResult Index()
{
    // Retrieve account from db
    var account = new Account() { Id = 1, Name = "Patrick", AboutMe = "I'm just another dude", ProfilePictureUrl = "", PrivacyLevel = PrivacyLevel.Private, Friends = new Collection<Account>() };
    // ViewModel abstracts the Entities and ensures behavour that only matters to the UI
    var accountViewModel = Mapper.Map<AccountViewModel>(account);

    return View(accountViewModel); // strongly typed view model
}

したがって、プロファイルインデックスビューは列挙型ビューモデルを使用できます

これが出力です

これで、プライバシー設定を変更したいときに、ドロップダウンで新しい値を送信できる新しいEditAccountViewModelを作成できます。

public class EditAccountViewModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string AboutMe { get; set; }
    public int NewSelectedPrivacyLevel { get; set; }
    public PrivacyLevelViewModel SelectedPrivacyLevel { get; set; }

    public SelectList PrivacyLevels
    {
        get
        {
            var items = Enum.GetValues(typeof (PrivacyLevelViewModel))
                .Cast<PrivacyLevelViewModel>()
                .Select(viewModel => new PrivacyLevelSelectItemViewModel()
                {
                    Text = viewModel.DescriptionAttr(),
                    Value = (int)viewModel,
                });

            //SelectPrivacyLevel was mapped by AutoMapper in the profile from 
            //original entity value to this viewmodel
            return new SelectList(items, "Value", "Text", (int) SelectedPrivacyLevel);
        }
    }
}

変更した新しい値の投稿を送信したら、興味深い部分は、更新されたプライバシー設定を使用してデータベースから「実際の」エンティティを変更する方法です。

フォームを編集アクションに送信すると、元の実際のdbエンティティを取得し、ViewModelの状態が有効な場合は変更をマージできます。

AutoMapperを使用すると、ViewModelsをエンティティにマッピングする方法を構成できます。一部のプロパティを整数エンティティからビューモデルの文字列値に変更する必要がある場合は、列挙型を実際には「ビュー」の文字列にし、列挙型の列挙型のみにする必要があります。 db、自動マッパーを使用すると、これらすべてのシナリオを構成できます。ビューモデルのプロパティ名/キャメルケースが大文字と同じである場合は、慣例により「すべての単一プロパティ」を構成する必要はありません。

最後に、これらのプロファイルを使用する前に、global.asaxやMainなどのアプリケーションエントリポイントでプロファイルをロードする必要があります。

AutoMapperは、アプリケーションで定義されたあらゆる種類のプロファイルをロードするために1回だけ「構成」する必要があります。いくつかのリフレクションを使用すると、次のコードを使用してアセンブリ内のすべてのプロファイルをロードできます。

public class AutoMapperConfig
{
    public static void RegisterConfig()
    {
        Mapper.Initialize(config => GetConfiguration(Mapper.Configuration));
    }

    private static void GetConfiguration(IConfiguration configuration)
    {
        configuration.AllowNullDestinationValues = true;
        configuration.AllowNullCollections = true;

        IEnumerable<Type> profiles = Assembly.GetExecutingAssembly().GetTypes().Where(type => typeof(Profile).IsAssignableFrom(type));

        foreach (var profile in profiles)
        {
            configuration.AddProfile(Activator.CreateInstance(profile) as Profile);
        }
    }
}

global.asaxで構成を呼び出します。

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    WebApiConfig.Register(GlobalConfiguration.Configuration);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    AutoMapperConfig.RegisterConfig(); // AutoMapperConfig.cs
}

AutoMapperの使用方法と、AutoMapperがどのように役立つかについての詳細は、次の場所にあります。

AutoMapper Github

于 2013-03-18T15:25:07.747 に答える
2

結局、私ははるかに簡単な解決策を思いつきました。列挙型の説明を取得するために拡張メソッドを使用しただけです。また、ローカリゼーションが非常に簡単になったので、リソース文字列を使用できました。

public static string Description(this PrivacyLevel level) {
  switch (level) {
    case PrivacyLevel.Public:
      return Resources.PrivacyPublic;
    case PrivacyLevel.FriendsOnly:
      return Resources.PrivacyFriendsOnly;
    case PrivacyLevel.Private:
      return Resources.PrivacyPrivate;
    default:
      throw new ArgumentOutOfRangeException("level");
  }
}
于 2013-10-20T14:39:26.620 に答える
0

他のアイデア:byte PrivacyLevelByteEFクラスで使用します。partial classプロパティを定義する特定のモデルに追加を作成します

PrivacyLevel PrivacyLevelEnum
{
    get { return (PrivacyLevel)PrivacyLevelByte; }
    set { PrivacyLevelByte = (byte)value;}
}

PrivacyLevelEFデザイナーではなく、コードで列挙型を定義します。これにより、任意の属性を処理できますが、EFモデルの列挙型プロパティが提供されます。

于 2013-12-21T16:22:02.650 に答える