15

(DTO と AutoMapper を使用して) 機能する解決策を見つけました。これを以下に再現しますが、問題に対するさまざまなアプローチを例とともにリストした回答を希望します。これは、受け取った場合は回答としてマークされます。

私のエンティティ モデルには、子エンティティから親エンティティに移動するナビゲーション プロパティがあります。私のプロジェクトは順調に機能していました。その後、単体テストに AutoFixture を使用し始めましたが、テストは失敗し、AutoFixture は循環参照があると言いました。

ここで、このような循環参照ナビゲーション プロパティは Entity Framework 内で問題ないことに気付きましたが、この投稿 ( AutoFixture で複雑な子を作成するときに親プロパティの値を使用する) を見つけました。ここで、AutoFixture の作成者である Mark Seemann は次のように述べています。

「記録のために、私は何年も循環参照を使用して API を作成していないため、これらの親子関係を回避することは十分に可能です。」

したがって、子/親の関係を回避するためにドメイン モデルをリファクタリングする方法を理解したいと思います。

以下は、問題のエンティティ クラス、リポジトリ メソッド、およびビューで循環参照を引き起こすプロパティの使用方法です。 完璧な答えは、例を挙げて選択できるさまざまなオプションと、各アプローチの基本的な長所/短所を説明することです.

注: 循環参照の原因となっているプロパティは、UserTeam モデルの User です。

モデル:

public class UserProfile
{
    public UserProfile()
    {
        UserTeams = new HashSet<UserTeam>();
        Games = new HashSet<Game>();
    }

    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }
    public string UserName { get; set; }       

    public virtual ICollection<UserTeam> UserTeams { get; set; }
    public virtual ICollection<Game> Games { get; set; }
}


public class Game
{
    public Game()
    {
        UserTeams = new HashSet<UserTeam>();
    }

    public int Id { get; set; }
    public int CreatorId { get; set; }

    public virtual ICollection<UserTeam> UserTeams { get; set; }
}


public class UserTeam
{
    public UserTeam()
    {
        UserTeam_Players = new HashSet<UserTeam_Player>();
    }

    public int Id { get; set; }
    public int UserId { get; set; }
    public int GameId { get; set; }

    public virtual UserProfile User { get; set; }
    public virtual ICollection<UserTeam_Player> UserTeam_Players { get; set; }
}

リポジトリ方式

public IEnumerable<Game> GetAllGames()
    {
        using (DataContext)
        {             
            var _games = DataContext.Games
                 .Include(x => x.UserTeams)
                 .Include(x => x.UserTeams.Select(y => y.User))
                 .ToList();
            if (_games == null)
            {
                // log error
                return null;
            }
            return _games;
        }
    }

意見

@model IEnumerable<Game>
@foreach (var item in Model){
    foreach (var userteam in item.UserTeams){
        <p>@userteam.User.UserName</p>
    }
}

ここで、「ユーザー」ナビゲーション プロパティを削除すると、「@userteam.User.UserName」を実行できなくなります。

では、ドメイン モデルをリファクタリングして循環参照を削除し、ゲームを簡単にループして UserTeam.User.Username のようなことを行うにはどうすればよいでしょうか?

4

3 に答える 3

1

(DTO と AutoMapper を使用して) 機能する解決策を見つけました。これを以下に再現しますが、問題に対するさまざまなアプローチを例とともにリストした回答を希望します。特に、これが望ましい解決策であるか、またはすべきかどうかナビゲーション プロパティをそのまま使用し、AutoFixture を取り除き、json のシリアル化に関しては、他の回避策 (属性など) を利用するだけです...

そこで、View Model にいくつかのクラスを追加しました。

public class GameDTO
{
    public int Id { get; set; }
    public int CreatorId { get; set; }

    public ICollection<UserTeamDTO> UserTeamsDTO { get; set; }
}

public class UserTeamDTO : UserTeam
{
    public UserProfile User { get; set; }
}

また、私のコントローラーでは、AutoMapper を使用して Game / UserTeam オブジェクトをリポジトリから DTO オブジェクトにマップし、IList _gamesDto をビューに返します。

var _games = _gameRepository.GetAllGames();

IList<GameDTO> _gamesDto = new List<GameDTO>();
IList<UserTeamDTO> _userteamsDto = new List<UserTeamDTO>();
GameDTO _gameDto = new GameDTO();
UserTeamDTO _userteamDto = new UserTeamDTO();
Mapper.CreateMap<Game, GameDTO>();
Mapper.CreateMap<UserTeam, UserTeamDTO>();

foreach (Game _game in _games)
{
    foreach (UserTeam _userteam in _game.UserTeams)
    {
        _userteamDto = Mapper.Map<UserTeamDTO>(_userteam);
        _userteamDto.User = _userRepository.GetUser(_userteam.UserId);
        _userteamsDto.Add(_userteamDto);
    }

    _gameDto = Mapper.Map<GameDTO>(_game);
    _gameDto.UserTeamsDTO = _userteamsDto;
    _gamesDto.Add(_gameDto);
}
于 2013-11-07T17:37:24.510 に答える
1

最近、JSON オブジェクトのシリアル化にも影響を与える同様の問題がありました。データ モデルから循環参照を削除することにしました。

最初に、循環参照を作成していた冗長なナビゲーション プロパティを削除しました。得られたデータのツリーが理にかなっていることを確認しました。これにより、どのオブジェクトがどの関係を所有しているかを明確にすることができました。

これにより、EF は私の関係について自動的に判断できなくなりました。FluentAPI を使用して、1 対多および多対多の関係を指定する必要がありました。ここで解決策を見つけました: https://stackoverflow.com/a/16719203/1887885

これが役に立てば幸いです。

于 2015-03-24T15:35:02.207 に答える