إنشاء نموذج مجال بدون مراجع دائرية في إطار الكيان

StackOverflow https://stackoverflow.com/questions/19840537

  •  29-07-2022
  •  | 
  •  

سؤال

لقد وجدت حلاً يعمل (باستخدام DTOs و Automapper) ، وهو مستنسخ أدناه ، لكنني أفضل إجابة تسرد طرق مختلفة للمشكلة مع أمثلة وسيتم تمييز هذا كإجابة إذا تم استلامها.

في نموذج الكيان الخاص بي ، لدي خاصية تنقل تنتقل من كيان طفل إلى كيان الوالدين. كان مشروعي يعمل بسباحة. ثم بدأت في استخدام AutoFixture لاختبار الوحدة ، وفشل الاختبار ، Autofixture قائلاً إن لدي مرجع دائري.

الآن ، أدرك أن خصائص الملاحة المرجعية الدائرية مثل هذه هي على ما يرام في إطار الكيان ، لكنني وجدت هذا المنشور (استخدم قيمة خاصية الأصل عند إنشاء طفل معقد في Autofixture) ، حيث ينص مارك سيمان ، خالق AutoFixture:

"بالنسبة للسجل ، لم أكتب واجهة برمجة تطبيقات مع مرجع دائري لسنوات ، لذلك من الممكن تمامًا تجنب علاقات الوالدين/الطفل."

لذلك ، أريد أن أفهم كيف يمكن إعادة بناء نموذج المجال لتجنب علاقات الطفل/الوالدين.

فيما يلي فئات الكيان المعنية ، طريقة المستودع ، وكيف أستخدم الخاصية التي تسبب المرجع الدائري في رأيي. إن الإجابة المثالية تفسر الخيارات المختلفة التي يمكنني الاختيار من بينها مع أمثلة ، و Pros/سلبيات كل نهج.

ملاحظة: الخاصية التي تسبب المرجع الدائري هي المستخدم ، في نموذج USERTEAM.

عارضات ازياء:

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؟

هل كانت مفيدة؟

المحلول

كان لدي مشكلة مماثلة مع Autofixture و entityframework منذ فترة. كان الحل الخاص بي هو إضافة امتداد إلى AutoFixture ، مما يتيح لك بناء SUT مع بعض العلامات. تم تبني هذا التمديد مؤخرًا في AutoFixture.

لكنني أفهم أن سؤالك لم يكن يتعلق بكيفية جعل تلقائيات Autofixture بناء هياكل البيانات العودية ، وهو أمر ممكن بالفعل ، ولكن كيفية إنشاء نماذج المجال دون عودة.

أولاً ، لديك هياكل شجرة أو رسم بياني. هنا أي شيء سوى العودية يعني عدم التوجيه من خلال معرفات العقدة الفضفاضة. بدلاً من تحديد الارتباط ، يجب عليك اجتياز الاستعلام عن طريق الأشجار أو ذاكرة التخزين المؤقت كل شيء وتجريره عن طريق البحث في العقدة ، والذي قد يكون غير عملي اعتمادًا على حجم الأشجار. هنا من المريح للغاية جعل EF القيام بالعمل من أجلك.

الهيكل المشترك الآخر هو بنية ملاحية ثنائية الاتجاه مماثلة لسيناريو المستخدم / اللعبة. هنا لا يكون من غير المريح تقليم تدفق التنقل إلى اتجاه واحد. إذا حذفت اتجاه واحد ، على سبيل المثال من اللعبة إلى الفريق ، لا يزال بإمكانك بسهولة الاستعلام عن جميع الفرق لمباراة معينة. لذلك: لدى المستخدم قائمة بالألعاب وقائمة الفرق. لدى الفريق قائمة بالألعاب. الألعاب ليس لها إشارة ملاحية إلى أي منهما. للحصول على جميع المستخدمين للحصول على لعبة معينة ، يمكنك كتابة شيء مثل:

var users = (from user in DataContext.Users
            from game in user.Games
            where game.Name == 'Chess'
            select user).Distinct()

نصائح أخرى

لقد وجدت حلاً يعمل (باستخدام DTOs و Automapper) ، وهو مستنسخ أدناه ، لكنني ما زلت أفضل إجابة تسرد طرق مختلفة للمشكلة مع أمثلة ، على وجه الخصوص ما إذا كان هذا هو الحل المرغوب فيه ، أو ما إذا كان ينبغي علي التمسك بخصائص التنقل كما كانت ، تخلص من Autofixture ، وعندما يتعلق الأمر بالتسلسل لـ JSON ، استخدم فقط العمل الآخر (السمات وما إلى ذلك) ...

لذلك ، في نموذج العرض الخاص بي ، أضفت بعض الفصول:

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 لرسم خريطة للكائنات / USERTEAM من المستودع إلى كائنات DTO الخاصة بي ، وإرجاع _gamesdto Ilist إلى العرض.

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);
}

واجهت مشكلة مماثلة مؤخرًا والتي أثرت أيضًا على تسلسل كائنات JSON. قررت إزالة المراجع الدائرية من نموذج البيانات الخاص بي.

قمت أولاً بإزالة خصائص الملاحة الزائدة التي كانت تخلق المراجع الدائرية. لقد تأكدت من أن شجرة البيانات الناتجة الخاصة بي كانت منطقية. هذا سمح لي أن أوضح الأشياء التي تملك العلاقات.

هذا أيضًا جعل EF غير قادر على التفكير تلقائيًا في علاقاتي. اضطررت إلى تحديد العلاقات الواحدة والعديد من العدد باستخدام Fluentapi. لقد وجدت حلاً هنا: https://stackoverflow.com/a/16719203/1887885

أتمنى أن يكون هذا مفيدًا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top